-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sync APIs #6
Comments
Hi @ppcano 👋🏻 Thank you so much for your input, it's been really useful, and triggered productive discussions and investigations on the backstage 🙇🏻 While you're right, nor k6, nor Goja, support the This being said, following the introduction of the event loop, although it might not be feature-complete yet, we consider the future of k6 modules is asynchronous. xk6-redis is making its way to becoming a core extension, and the move to a Thus, how do we intend to move forward considering the issue you've raised, while also respecting the technical plan that led to switching to asynchronous API in the first place?
Here's a more full-fledged example demonstrating how to address the sort of issues you pointed out in your comment: import { check } from 'k6'
import http from 'k6/http'
import redis from 'k6/x/redis'
import exec from 'k6/execution'
export const options = {
scenarios: {
redisPerformance: {
executor: 'shared-iterations',
vus: 10,
iterations: 200,
exec: 'measureRedisPerformance',
},
usingRedisData: {
executor: 'shared-iterations',
vus: 10,
iterations: 200,
exec: 'measureUsingRedisData',
},
},
}
// Instantiate a new redis client
const redisClient = new redis.Client({
addrs: new Array('localhost:6379'),
password: 'foobar',
})
// Prepare an array of crocodile ids for later use
// in the context of the measureUsingRedisData function.
const crocodileIDs = new Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
export function measureRedisPerformance() {
// VUs are executed in a parallel fashion,
// thus, to ensure that parallel VUs are not
// modifying the same key at the same time,
// we use keys indexed by the VU id.
const key = `foo-${exec.vu.idInTest}`
redisClient
.set(`foo-${exec.vu.idInTest}`, 1)
.then(() => redisClient.get(`foo-${exec.vu.idInTest}`))
.then((value) => redisClient.incrBy(`foo-${exec.vu.idInTest}`, value))
.then((_) => redisClient.del(`foo-${exec.vu.idInTest}`))
.then((_) => redisClient.exists(`foo-${exec.vu.idInTest}`))
.then((exists) => {
if (exists !== 0) {
throw new Error('foo should have been deleted')
}
})
}
export function setup() {
redisClient.sadd('crocodile_ids', ...crocodileIDs)
}
export function measureUsingRedisData() {
// Pick a random crocodile id from the dedicated redis set,
// we have filled in setup().
redisClient
.srandmember('crocodile_ids')
.then((randomID) => {
const url = `https://test-api.k6.io/public/crocodiles/${randomID}`
const res = http.get(url)
check(res, {
'status is 200': (r) => r.status === 200,
'content-type is application/json': (r) =>
r.headers['content-type'] === 'application/json',
})
return url
})
.then((url) => redisClient.hincrby('k6_crocodile_fetched', url, 1))
}
export function teardown() {
redisClient.del('crocodile_ids')
}
export function handleSummary(data) {
redisClient
.hgetall('k6_crocodile_fetched')
.then((fetched) => Object.assign(data, { k6_crocodile_fetched: fetched }))
.then((data) => redisClient.set(`k6_report_${Date.now()}`, JSON.stringify(data)))
.then(() => redisClient.del('k6_crocodile_fetched'))
} Note how we, for instance, call the (synchronous) PS: In your specific counter example, that would indeed translate to writing most of the test as a promise chain: if everything is a promise, then nothing is, and that's basically what we're shooting for 🙇🏻 |
As raised by #6, the use of xk6-redis' module APIs was not clear, nor thorough enough; especially in a context where it would need to be used side by side with synchronous APIs.
As raised by #6, the use of xk6-redis' module APIs was not clear, nor thorough enough; especially in a context where it would need to be used side by side with synchronous APIs.
As raised by #6, the use of xk6-redis' module APIs was not clear, nor thorough enough; especially in a context where it would need to be used side by side with synchronous APIs.
Closing it as |
#4 brought async support to most of the xk6-redis APIs. Currently,
await
is not currently supported, so there is no way to interact with Redis synchronously for most APIs.I discussed this briefly with @mstoykov and @sniku. It seems that async APIs does not allow using using Redis for some particular cases.
The main reason is that Promise handlers are always executed after the VU code. Let's show one example:
In this case, the execution will always be in this order:
before async 1 exit VU code 1 promise callback 1
With async APIs, the result of a promise cannot change the VU execution code (outside the promise handler). Users could not do something like:
This issue requests to provide "sync" support for Redis APIs to not limit the potential of using Redis in k6 tests. For example, to share data across VUs in your load test.
cc @oleiade
The text was updated successfully, but these errors were encountered: