Skip to content

Commit 13e7b4a

Browse files
claudenicktrn
authored andcommitted
fix: resolve task TTL even when queue is overridden
1 parent 5a68fa0 commit 13e7b4a

File tree

2 files changed

+30
-32
lines changed

2 files changed

+30
-32
lines changed

apps/webapp/CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ Some services (e.g., `cancelTaskRun.server.ts`, `batchTriggerV3.server.ts`) bran
6161

6262
The `triggerTask.server.ts` service is the **highest-throughput code path** in the system. Every API trigger call goes through it. Keep it fast:
6363

64-
- **Do NOT add database queries** to the trigger path. The only acceptable DB query for task defaults (TTL, etc.) is the single existing `backgroundWorkerTask.findFirst()` call with a minimal `select`.
64+
- **Do NOT add database queries** to the trigger path. The only acceptable DB query for task defaults (TTL, etc.) is the single existing `backgroundWorkerTask.findFirst()` call in the queue concern. Piggyback on it instead of adding new queries.
6565
- **Two-stage resolution pattern**: Task metadata is resolved in two stages by design:
6666
1. **Trigger time** (`triggerTask.server.ts`): Only TTL is resolved from task defaults. Everything else uses whatever the caller provides.
6767
2. **Dequeue time** (`dequeueSystem.ts`): Full `BackgroundWorkerTask` is loaded and retry config, machine config, maxDuration, etc. are resolved against task defaults.

apps/webapp/app/runEngine/concerns/queues.server.ts

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,35 @@ export class DefaultQueueManager implements QueueManager {
7979
if (lockedBackgroundWorker) {
8080
// Task is locked to a specific worker version
8181
const specifiedQueueName = extractQueueName(request.body.options?.queue);
82+
83+
// Always fetch the task to get TTL (and default queue if no override)
84+
const lockedTask = await this.prisma.backgroundWorkerTask.findFirst({
85+
where: {
86+
workerId: lockedBackgroundWorker.id,
87+
runtimeEnvironmentId: request.environment.id,
88+
slug: request.taskId,
89+
},
90+
include: {
91+
queue: true,
92+
},
93+
});
94+
95+
if (!lockedTask) {
96+
throw new ServiceValidationError(
97+
`Task '${request.taskId}' not found on locked version '${lockedBackgroundWorker.version ?? "<unknown>"
98+
}'.`
99+
);
100+
}
101+
102+
taskTtl = lockedTask.ttl;
103+
82104
if (specifiedQueueName) {
83-
// A specific queue name is provided
105+
// A specific queue name is provided, validate it exists for the locked worker
84106
const specifiedQueue = await this.prisma.taskQueue.findFirst({
85-
// Validate it exists for the locked worker
86107
where: {
87108
name: specifiedQueueName,
88109
runtimeEnvironmentId: request.environment.id,
89-
workers: { some: { id: lockedBackgroundWorker.id } }, // Ensure the queue is associated with any task of the locked worker
110+
workers: { some: { id: lockedBackgroundWorker.id } },
90111
},
91112
});
92113

@@ -100,25 +121,6 @@ export class DefaultQueueManager implements QueueManager {
100121
queueName = specifiedQueue.name;
101122
lockedQueueId = specifiedQueue.id;
102123
} else {
103-
// No specific queue name provided, use the default queue for the task on the locked worker
104-
const lockedTask = await this.prisma.backgroundWorkerTask.findFirst({
105-
where: {
106-
workerId: lockedBackgroundWorker.id,
107-
runtimeEnvironmentId: request.environment.id,
108-
slug: request.taskId,
109-
},
110-
include: {
111-
queue: true,
112-
},
113-
});
114-
115-
if (!lockedTask) {
116-
throw new ServiceValidationError(
117-
`Task '${request.taskId}' not found on locked version '${lockedBackgroundWorker.version ?? "<unknown>"
118-
}'.`
119-
);
120-
}
121-
122124
if (!lockedTask.queue) {
123125
// This case should ideally be prevented by earlier checks or schema constraints,
124126
// but handle it defensively.
@@ -135,7 +137,6 @@ export class DefaultQueueManager implements QueueManager {
135137
// Use the task's default queue name
136138
queueName = lockedTask.queue.name;
137139
lockedQueueId = lockedTask.queue.id;
138-
taskTtl = lockedTask.ttl;
139140
}
140141
} else {
141142
// Task is not locked to a specific version, use regular logic
@@ -181,10 +182,7 @@ export class DefaultQueueManager implements QueueManager {
181182
const { queue } = body.options ?? {};
182183

183184
// Use extractQueueName to handle double-wrapped queue objects
184-
const queueName = extractQueueName(queue);
185-
if (queueName) {
186-
return { queueName };
187-
}
185+
const overriddenQueueName = extractQueueName(queue);
188186

189187
const defaultQueueName = `task/${taskId}`;
190188

@@ -197,7 +195,7 @@ export class DefaultQueueManager implements QueueManager {
197195
environmentId: environment.id,
198196
});
199197

200-
return { queueName: defaultQueueName };
198+
return { queueName: overriddenQueueName ?? defaultQueueName };
201199
}
202200

203201
const task = await this.prisma.backgroundWorkerTask.findFirst({
@@ -217,7 +215,7 @@ export class DefaultQueueManager implements QueueManager {
217215
environmentId: environment.id,
218216
});
219217

220-
return { queueName: defaultQueueName };
218+
return { queueName: overriddenQueueName ?? defaultQueueName };
221219
}
222220

223221
if (!task.queue) {
@@ -227,10 +225,10 @@ export class DefaultQueueManager implements QueueManager {
227225
queueConfig: task.queueConfig,
228226
});
229227

230-
return { queueName: defaultQueueName, taskTtl: task.ttl };
228+
return { queueName: overriddenQueueName ?? defaultQueueName, taskTtl: task.ttl };
231229
}
232230

233-
return { queueName: task.queue.name ?? defaultQueueName, taskTtl: task.ttl };
231+
return { queueName: overriddenQueueName ?? task.queue.name ?? defaultQueueName, taskTtl: task.ttl };
234232
}
235233

236234
async validateQueueLimits(

0 commit comments

Comments
 (0)