#How to handle per tenant queueing in v4?

1 messages · Page 1 of 1 (latest)

bleak flume
#

I've currently upgraded to v4 and was leaning heavily on per-tenant queueing before.

Now, this syntax has changed and I'm not sure if I'm still implementing the per-tenant queueing correctly, since the docs still seem to apply the v3 syntax.

How I handle it now in v4:

  1. Define the queue on task-level:
// Define queue for AdminPulse data updates
const updateAdminPulseQueue = queue({
  name: "update-adminpulse-data",
  concurrencyLimit: 1,
});

export const updateAdminPulseDataTask = schemaTask({
  id: "update-admin-pulse-data",
  queue: updateAdminPulseQueue,
  schema: payloadSchema,
  ...
  1. When batch-executing, only add the queue name and the concurrency key, my expectation is that in this case, multiple tasks of update-adminpulse-data will run at the same time, because one per concurrencyKey is executing.
  const batchHandles = await updateAdminPulseDataTask.batchTrigger([
      ...adminPulseIntegrations.map((integration) => {
        return {
          payload: {
            tenantCode: integration.firm.kindeOrganizationCode,
            tenantHandle: integration.firm.kindeOrganizationHandle,
            integrationId: integration.integrationId,
            featureFlags: {
              hasProfitabilityDashboardsMvpFeatureFlag:
                integration.hasProfitabilityDashboardsMvpFeatureFlag,
            },
          },
          queue: "update-admin-pulse-data",
          concurrencyKey: integration.firm.kindeOrganizationHandle,
          idempotencyKey: `update-admin-pulse-data-integration-${integration.integrationId}`,
          options: {
            tags: [
              integration.firm.kindeOrganizationCode,
              integration.firm.kindeOrganizationHandle,
              `ADMINPULSE_UPDATE:${integration.firm.kindeOrganizationHandle}`,
            ],
          },
        };
      }),
    ]);

Is this correct?

acoustic cradleBOT
#

Hi @bleak flume. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

Your approach to per-tenant queueing in v4 is mostly correct, but there are some important changes in v4 you need to be aware of:

1. Queue Definition

You are correctly defining the queue ahead of time using the queue function and assigning it to the task. In v4, queues must be defined before use; you can no longer create or update queues on-the-fly by specifying a name and concurrency limit in the trigger options. This is a breaking change from v3. Your code for defining the queue and assigning it to the task is correct:

const updateAdminPulseQueue = queue({
  name: "update-adminpulse-data",
  concurrencyLimit: 1,
});

export const updateAdminPulseDataTask = schemaTask({
  id: "update-admin-pulse-data",
  queue: updateAdminPulseQueue,
  schema: payloadSchema,
  // ...
});

Breaking changes: Queue changes

2. Triggering with concurrencyKey

In v4, you should specify the queue by name (since it's already defined), and you can use the concurrencyKey to achieve per-tenant concurrency. This will ensure that only one run per unique concurrencyKey (e.g., per tenant) is executing at a time, while allowing multiple tenants to run in parallel. Your usage here is correct:

{
  payload: { /* ... */ },
  queue: "update-adminpulse-data",
  concurrencyKey: integration.firm.kindeOrganizationHandle,
  idempotencyKey: `update-admin-pulse-data-integration-${integration.integrationId}`,
  options: { /* ... */ },
}

Concurrency keys and per-tenant queuing

3. Batch Triggering

#

Your use of batchTrigger with an array of payloads, each specifying a concurrencyKey, is the correct way to achieve per-tenant queueing in v4. Each tenant (identified by a unique concurrencyKey) will have its own concurrency slot within the defined queue, and the queue's concurrencyLimit will still apply globally.

4. Important v4 Notes

  • You must not specify a new queue name or concurrency limit in the trigger options unless the queue is already defined. Only use the name of a pre-defined queue.
  • The concurrency limit you set on the queue applies to the total number of runs executing in that queue, but the concurrencyKey ensures only one run per key (tenant) is active at a time.
  • The syntax for passing the queue name and concurrency key in the trigger options is correct in your example.

Summary

Your implementation matches the v4 requirements for per-tenant queueing: define the queue ahead of time, assign it to the task, and use the concurrencyKey when triggering. This will ensure that only one run per tenant is active at a time, while allowing multiple tenants to process in parallel, up to the queue's concurrency limit.

If you want to reference the official documentation for these changes, see the v4 breaking changes on queues and concurrency keys and per-tenant queuing.

If you have further questions about edge cases or advanced usage, let me know!

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@bleak flume Kapa.ai is still learning and improving, please let me know how I did by reacting below.

orchid moss
#

@bleak flume yup you are correct, you can still use concurrencyKey like you said, each concurrencyKey will get up to 1 "concurrency slot" of that task at a time. The only difference now is you have to predefine the queue along with the concurrency limit, we don't support passing in the concurrencyLimit at trigger time