k6 icon indicating copy to clipboard operation
k6 copied to clipboard

SharedArray does not work with async functions

Open mstoykov opened this issue 1 year ago • 2 comments

import {SharedArray} from "k6/data";
let s = new SharedArray("cool", async() => {
  return [1, 2, 3];
})
export default function  () {
  console.log(s);
}

Will give you

ERRO[0000] GoError: only arrays can be made into SharedArray

But it likely should work.

There is currently no real reason to use async code withing SharedArray, but it might based on #2043 and specifically thsi comment.

Note: this does mean that SharedArray will also have to return a promise or have an async variant

mstoykov avatar Apr 06 '23 13:04 mstoykov

I have another use case that would make support of an async function for SharedArray useable for me. We are using the webcrypto experimental package to generate a shared array of "user" objects, each with a uuid identifier and a signed JWT token. I'm unable to generate/sign a JWT as part of the SharedArray loader function because the webcrypto subtle.sign() function is async and I cannot call this within the loader function.

If the SharedArray loader function allowed an async function, then this would be easily doable. Because of this, I cannot use a SharedArray to populate anything that the crypto.subtle.sign() function produces or call any other functions that are async.

What this leaves me having to do is to return the generated "users" as a response to the setup function and accept the generated "users" as an argument to the default function, which means that I have a fresh copy of this potentially large set of users for each VU.

JeffBNimble avatar Jun 24 '24 21:06 JeffBNimble

Hi @JeffBNimble, thanks for the input - this does seem like a good case for this functionality.

If you want you can work on this, but I will recommend making a new AsyncSharedArray - that always returns a promise.

As part of #3265 we will be getting top-level-await which is arguably currently a big UX problem for anything that uses async in the top.

Given the recent goja fork and the ongoing work on ESM - I don't think I will be able to work on it. It also happens to be vacation season, so we already have lesser capacity within the team :(. So no ETA on when we will be able to work on this.

My hacky workaround for now will be to abuse __VU as in

import { SharedArray } from "k6/data";
let data;
if (__VU == 0) { // first init context (among other things)
	(async () => {
		// generate what you need
		let generated_data = await [1, 2, 3, 4, 5]

		new SharedArray("coolname", () => { return generated_data; })
	})()
} else {
	data = new SharedArray("coolname", () => { throw "this will never be executed as shared array was already defined" })
}

export default () => {
	console.log(data[1]);
}

As you can see you need to quite a bunch of stuff in order to use async/await in the top level currently.

You might also want to look into using the old k6/crypto if that works for your use case https://gist.github.com/robingustafsson/7dd6463d85efdddbb0e4bcd3ecc706e1

mstoykov avatar Jun 25 '24 09:06 mstoykov