duron 0.3.0-beta.12 → 0.3.0-beta.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/action.d.ts +202 -13
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +13 -128
- package/dist/adapters/postgres/base.d.ts +14 -5
- package/dist/adapters/postgres/base.d.ts.map +1 -1
- package/dist/adapters/postgres/base.js +84 -17
- package/dist/adapters/postgres/schema.d.ts +15 -0
- package/dist/adapters/postgres/schema.d.ts.map +1 -1
- package/dist/adapters/postgres/schema.default.d.ts +15 -0
- package/dist/adapters/postgres/schema.default.d.ts.map +1 -1
- package/dist/adapters/postgres/schema.js +2 -0
- package/dist/adapters/schemas.d.ts +4 -0
- package/dist/adapters/schemas.d.ts.map +1 -1
- package/dist/adapters/schemas.js +3 -0
- package/dist/client.d.ts +109 -14
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3 -64
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -1
- package/migrations/postgres/20260121134451_thankful_manta/migration.sql +2 -0
- package/migrations/postgres/20260121134451_thankful_manta/snapshot.json +1503 -0
- package/package.json +1 -1
- package/src/action.ts +254 -143
- package/src/adapters/postgres/base.ts +124 -21
- package/src/adapters/postgres/schema.ts +2 -0
- package/src/adapters/schemas.ts +3 -0
- package/src/client.ts +79 -26
|
@@ -141,7 +141,15 @@ export class PostgresBaseAdapter<Database extends DrizzleDatabase, Connection> e
|
|
|
141
141
|
*
|
|
142
142
|
* @returns Promise resolving to the job ID, or `null` if creation failed
|
|
143
143
|
*/
|
|
144
|
-
protected async _createJob({
|
|
144
|
+
protected async _createJob({
|
|
145
|
+
queue,
|
|
146
|
+
groupKey,
|
|
147
|
+
input,
|
|
148
|
+
timeoutMs,
|
|
149
|
+
checksum,
|
|
150
|
+
concurrencyLimit,
|
|
151
|
+
concurrencyStepLimit,
|
|
152
|
+
}: CreateJobOptions) {
|
|
145
153
|
const [result] = await this.db
|
|
146
154
|
.insert(this.tables.jobsTable)
|
|
147
155
|
.values({
|
|
@@ -152,6 +160,7 @@ export class PostgresBaseAdapter<Database extends DrizzleDatabase, Connection> e
|
|
|
152
160
|
status: JOB_STATUS_CREATED,
|
|
153
161
|
timeout_ms: timeoutMs,
|
|
154
162
|
concurrency_limit: concurrencyLimit,
|
|
163
|
+
concurrency_step_limit: concurrencyStepLimit,
|
|
155
164
|
})
|
|
156
165
|
.returning({ id: this.tables.jobsTable.id })
|
|
157
166
|
|
|
@@ -667,7 +676,8 @@ export class PostgresBaseAdapter<Database extends DrizzleDatabase, Connection> e
|
|
|
667
676
|
j.finished_at as "finishedAt",
|
|
668
677
|
j.created_at as "createdAt",
|
|
669
678
|
j.updated_at as "updatedAt",
|
|
670
|
-
j.concurrency_limit as "concurrencyLimit"
|
|
679
|
+
j.concurrency_limit as "concurrencyLimit",
|
|
680
|
+
j.concurrency_step_limit as "concurrencyStepLimit"
|
|
671
681
|
`),
|
|
672
682
|
)
|
|
673
683
|
|
|
@@ -1038,6 +1048,7 @@ export class PostgresBaseAdapter<Database extends DrizzleDatabase, Connection> e
|
|
|
1038
1048
|
createdAt: jobsTable.created_at,
|
|
1039
1049
|
updatedAt: jobsTable.updated_at,
|
|
1040
1050
|
concurrencyLimit: jobsTable.concurrency_limit,
|
|
1051
|
+
concurrencyStepLimit: jobsTable.concurrency_step_limit,
|
|
1041
1052
|
clientId: jobsTable.client_id,
|
|
1042
1053
|
durationMs,
|
|
1043
1054
|
})
|
|
@@ -1241,6 +1252,7 @@ export class PostgresBaseAdapter<Database extends DrizzleDatabase, Connection> e
|
|
|
1241
1252
|
createdAt: jobsTable.created_at,
|
|
1242
1253
|
updatedAt: jobsTable.updated_at,
|
|
1243
1254
|
concurrencyLimit: jobsTable.concurrency_limit,
|
|
1255
|
+
concurrencyStepLimit: jobsTable.concurrency_step_limit,
|
|
1244
1256
|
clientId: jobsTable.client_id,
|
|
1245
1257
|
durationMs,
|
|
1246
1258
|
})
|
|
@@ -1418,21 +1430,29 @@ export class PostgresBaseAdapter<Database extends DrizzleDatabase, Connection> e
|
|
|
1418
1430
|
|
|
1419
1431
|
/**
|
|
1420
1432
|
* Internal method to get spans for a job or step.
|
|
1433
|
+
* For step queries, uses a recursive CTE to find all descendant spans.
|
|
1421
1434
|
*/
|
|
1422
1435
|
protected async _getSpans(options: GetSpansOptions): Promise<GetSpansResult> {
|
|
1423
1436
|
const spansTable = this.tables.spansTable
|
|
1424
1437
|
const filters = options.filters ?? {}
|
|
1425
1438
|
|
|
1426
|
-
// Build WHERE clause
|
|
1427
|
-
const where = this._buildSpansWhereClause(options.jobId, options.stepId, filters)
|
|
1428
|
-
|
|
1429
1439
|
// Build sort
|
|
1430
1440
|
const sortInput = options.sort ?? { field: 'startTimeUnixNano', order: 'asc' }
|
|
1431
|
-
const sortFieldMap: Record<SpanSort['field'],
|
|
1432
|
-
name:
|
|
1433
|
-
startTimeUnixNano:
|
|
1434
|
-
endTimeUnixNano:
|
|
1441
|
+
const sortFieldMap: Record<SpanSort['field'], string> = {
|
|
1442
|
+
name: 'name',
|
|
1443
|
+
startTimeUnixNano: 'start_time_unix_nano',
|
|
1444
|
+
endTimeUnixNano: 'end_time_unix_nano',
|
|
1435
1445
|
}
|
|
1446
|
+
const sortField = sortFieldMap[sortInput.field]
|
|
1447
|
+
const sortOrder = sortInput.order === 'asc' ? 'ASC' : 'DESC'
|
|
1448
|
+
|
|
1449
|
+
// For step queries, use a recursive CTE to get descendant spans
|
|
1450
|
+
if (options.stepId) {
|
|
1451
|
+
return this._getStepSpansRecursive(options.stepId, sortField, sortOrder, filters)
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
// Build WHERE clause for job queries
|
|
1455
|
+
const where = this._buildSpansWhereClause(options.jobId, undefined, filters)
|
|
1436
1456
|
|
|
1437
1457
|
// Get total count
|
|
1438
1458
|
const total = await this.db.$count(spansTable, where)
|
|
@@ -1443,8 +1463,11 @@ export class PostgresBaseAdapter<Database extends DrizzleDatabase, Connection> e
|
|
|
1443
1463
|
}
|
|
1444
1464
|
}
|
|
1445
1465
|
|
|
1446
|
-
const
|
|
1447
|
-
const orderByClause =
|
|
1466
|
+
const sortFieldColumn = sortFieldMap[sortInput.field]
|
|
1467
|
+
const orderByClause =
|
|
1468
|
+
sortInput.order === 'asc'
|
|
1469
|
+
? asc(spansTable[sortFieldColumn as keyof typeof spansTable] as any)
|
|
1470
|
+
: desc(spansTable[sortFieldColumn as keyof typeof spansTable] as any)
|
|
1448
1471
|
|
|
1449
1472
|
const rows = await this.db
|
|
1450
1473
|
.select({
|
|
@@ -1483,6 +1506,89 @@ export class PostgresBaseAdapter<Database extends DrizzleDatabase, Connection> e
|
|
|
1483
1506
|
}
|
|
1484
1507
|
}
|
|
1485
1508
|
|
|
1509
|
+
/**
|
|
1510
|
+
* Get spans for a step using a recursive CTE to traverse the span hierarchy.
|
|
1511
|
+
* This returns the step's span and all its descendant spans (children, grandchildren, etc.)
|
|
1512
|
+
*/
|
|
1513
|
+
protected async _getStepSpansRecursive(
|
|
1514
|
+
stepId: string,
|
|
1515
|
+
sortField: string,
|
|
1516
|
+
sortOrder: string,
|
|
1517
|
+
_filters?: GetSpansOptions['filters'],
|
|
1518
|
+
): Promise<GetSpansResult> {
|
|
1519
|
+
const schemaName = this.schema
|
|
1520
|
+
|
|
1521
|
+
// Use a recursive CTE to find all descendant spans
|
|
1522
|
+
// 1. Base case: find the span with step_id = stepId
|
|
1523
|
+
// 2. Recursive case: find all spans where parent_span_id = span_id of a span we've already found
|
|
1524
|
+
const query = sql`
|
|
1525
|
+
WITH RECURSIVE span_tree AS (
|
|
1526
|
+
-- Base case: the span(s) for the step
|
|
1527
|
+
SELECT * FROM ${sql.identifier(schemaName)}.spans WHERE step_id = ${stepId}::uuid
|
|
1528
|
+
UNION ALL
|
|
1529
|
+
-- Recursive case: children of spans we've found
|
|
1530
|
+
SELECT s.* FROM ${sql.identifier(schemaName)}.spans s
|
|
1531
|
+
INNER JOIN span_tree st ON s.parent_span_id = st.span_id
|
|
1532
|
+
)
|
|
1533
|
+
SELECT
|
|
1534
|
+
id,
|
|
1535
|
+
trace_id as "traceId",
|
|
1536
|
+
span_id as "spanId",
|
|
1537
|
+
parent_span_id as "parentSpanId",
|
|
1538
|
+
job_id as "jobId",
|
|
1539
|
+
step_id as "stepId",
|
|
1540
|
+
name,
|
|
1541
|
+
kind,
|
|
1542
|
+
start_time_unix_nano as "startTimeUnixNano",
|
|
1543
|
+
end_time_unix_nano as "endTimeUnixNano",
|
|
1544
|
+
status_code as "statusCode",
|
|
1545
|
+
status_message as "statusMessage",
|
|
1546
|
+
attributes,
|
|
1547
|
+
events
|
|
1548
|
+
FROM span_tree
|
|
1549
|
+
ORDER BY ${sql.identifier(sortField)} ${sql.raw(sortOrder)}
|
|
1550
|
+
`
|
|
1551
|
+
|
|
1552
|
+
// Raw SQL returns numeric types as strings, so we type them as such
|
|
1553
|
+
const rows = (await this.db.execute(query)) as unknown as Array<{
|
|
1554
|
+
id: string | number
|
|
1555
|
+
traceId: string
|
|
1556
|
+
spanId: string
|
|
1557
|
+
parentSpanId: string | null
|
|
1558
|
+
jobId: string | null
|
|
1559
|
+
stepId: string | null
|
|
1560
|
+
name: string
|
|
1561
|
+
kind: string | number
|
|
1562
|
+
startTimeUnixNano: string | bigint | null
|
|
1563
|
+
endTimeUnixNano: string | bigint | null
|
|
1564
|
+
statusCode: string | number
|
|
1565
|
+
statusMessage: string | null
|
|
1566
|
+
attributes: Record<string, any>
|
|
1567
|
+
events: Array<{ name: string; timeUnixNano: string; attributes?: Record<string, any> }>
|
|
1568
|
+
}>
|
|
1569
|
+
|
|
1570
|
+
// Convert types: raw SQL returns numeric types as strings
|
|
1571
|
+
const spans = rows.map((row) => ({
|
|
1572
|
+
...row,
|
|
1573
|
+
// Convert id to number (bigserial comes as string from raw SQL)
|
|
1574
|
+
id: typeof row.id === 'string' ? Number.parseInt(row.id, 10) : row.id,
|
|
1575
|
+
// Convert kind and statusCode to proper types
|
|
1576
|
+
kind: (typeof row.kind === 'string' ? Number.parseInt(row.kind, 10) : row.kind) as 0 | 1 | 2 | 3 | 4,
|
|
1577
|
+
statusCode: (typeof row.statusCode === 'string' ? Number.parseInt(row.statusCode, 10) : row.statusCode) as
|
|
1578
|
+
| 0
|
|
1579
|
+
| 1
|
|
1580
|
+
| 2,
|
|
1581
|
+
// Convert BigInt to string for JSON serialization
|
|
1582
|
+
startTimeUnixNano: row.startTimeUnixNano?.toString() ?? null,
|
|
1583
|
+
endTimeUnixNano: row.endTimeUnixNano?.toString() ?? null,
|
|
1584
|
+
}))
|
|
1585
|
+
|
|
1586
|
+
return {
|
|
1587
|
+
spans,
|
|
1588
|
+
total: spans.length,
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1486
1592
|
/**
|
|
1487
1593
|
* Internal method to delete all spans for a job.
|
|
1488
1594
|
*/
|
|
@@ -1496,12 +1602,15 @@ export class PostgresBaseAdapter<Database extends DrizzleDatabase, Connection> e
|
|
|
1496
1602
|
}
|
|
1497
1603
|
|
|
1498
1604
|
/**
|
|
1499
|
-
* Build WHERE clause for spans queries.
|
|
1500
|
-
* When querying by jobId
|
|
1501
|
-
* as spans with that job
|
|
1605
|
+
* Build WHERE clause for spans queries (used for job queries only).
|
|
1606
|
+
* When querying by jobId, we find all spans that share the same trace_id
|
|
1607
|
+
* as spans with that job. This includes spans from external libraries that
|
|
1502
1608
|
* don't have the duron.job.id attribute but are part of the same trace.
|
|
1609
|
+
*
|
|
1610
|
+
* Note: Step queries are handled separately by _getStepSpansRecursive using
|
|
1611
|
+
* a recursive CTE to traverse the span hierarchy.
|
|
1503
1612
|
*/
|
|
1504
|
-
protected _buildSpansWhereClause(jobId?: string,
|
|
1613
|
+
protected _buildSpansWhereClause(jobId?: string, _stepId?: string, filters?: GetSpansOptions['filters']) {
|
|
1505
1614
|
const spansTable = this.tables.spansTable
|
|
1506
1615
|
|
|
1507
1616
|
// Build condition for finding spans by trace_id (includes external spans)
|
|
@@ -1514,12 +1623,6 @@ export class PostgresBaseAdapter<Database extends DrizzleDatabase, Connection> e
|
|
|
1514
1623
|
spansTable.trace_id,
|
|
1515
1624
|
this.db.select({ traceId: spansTable.trace_id }).from(spansTable).where(eq(spansTable.job_id, jobId)),
|
|
1516
1625
|
)
|
|
1517
|
-
} else if (stepId) {
|
|
1518
|
-
// Find all spans that share a trace_id with any span that has this step_id
|
|
1519
|
-
traceCondition = inArray(
|
|
1520
|
-
spansTable.trace_id,
|
|
1521
|
-
this.db.select({ traceId: spansTable.trace_id }).from(spansTable).where(eq(spansTable.step_id, stepId)),
|
|
1522
|
-
)
|
|
1523
1626
|
}
|
|
1524
1627
|
|
|
1525
1628
|
return and(
|
|
@@ -37,6 +37,7 @@ export default function createSchema(schemaName: string) {
|
|
|
37
37
|
finished_at: timestamp('finished_at', { withTimezone: true }),
|
|
38
38
|
client_id: text('client_id'),
|
|
39
39
|
concurrency_limit: integer('concurrency_limit').notNull().default(10),
|
|
40
|
+
concurrency_step_limit: integer('concurrency_step_limit').notNull().default(100),
|
|
40
41
|
created_at: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
41
42
|
updated_at: timestamp('updated_at', { withTimezone: true })
|
|
42
43
|
.notNull()
|
|
@@ -59,6 +60,7 @@ export default function createSchema(schemaName: string) {
|
|
|
59
60
|
index('idx_jobs_client_id').on(table.client_id),
|
|
60
61
|
index('idx_jobs_checksum').on(table.checksum),
|
|
61
62
|
index('idx_jobs_concurrency_limit').on(table.concurrency_limit),
|
|
63
|
+
index('idx_jobs_concurrency_step_limit').on(table.concurrency_step_limit),
|
|
62
64
|
// Composite indexes
|
|
63
65
|
index('idx_jobs_action_status').on(table.action_name, table.status),
|
|
64
66
|
index('idx_jobs_action_group').on(table.action_name, table.group_key),
|
package/src/adapters/schemas.ts
CHANGED
|
@@ -45,6 +45,7 @@ export const JobSchema = z.object({
|
|
|
45
45
|
createdAt: DateSchema,
|
|
46
46
|
updatedAt: DateSchema,
|
|
47
47
|
concurrencyLimit: z.coerce.number(),
|
|
48
|
+
concurrencyStepLimit: z.coerce.number(),
|
|
48
49
|
clientId: z.string().nullable().optional(),
|
|
49
50
|
/** Duration in milliseconds (finishedAt - startedAt). Null if job hasn't finished. */
|
|
50
51
|
durationMs: z.coerce.number().nullable().default(null),
|
|
@@ -146,6 +147,8 @@ export const CreateJobOptionsSchema = z.object({
|
|
|
146
147
|
timeoutMs: z.number(),
|
|
147
148
|
/** The concurrency limit for this job's group */
|
|
148
149
|
concurrencyLimit: z.number(),
|
|
150
|
+
/** The concurrency limit for steps within this job */
|
|
151
|
+
concurrencyStepLimit: z.number(),
|
|
149
152
|
})
|
|
150
153
|
|
|
151
154
|
export const RecoverJobsOptionsSchema = z.object({
|
package/src/client.ts
CHANGED
|
@@ -130,93 +130,145 @@ export interface TelemetryOptions {
|
|
|
130
130
|
serviceName?: string
|
|
131
131
|
}
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Base configuration options for a Duron client instance.
|
|
135
|
+
* These options control job fetching, concurrency, and recovery behavior.
|
|
136
|
+
*/
|
|
137
|
+
export interface BaseOptionsInput {
|
|
134
138
|
/**
|
|
135
139
|
* Unique identifier for this Duron instance.
|
|
136
140
|
* Used for multi-process coordination and job ownership.
|
|
137
|
-
*
|
|
141
|
+
* If not provided, a random UUID will be generated.
|
|
142
|
+
*
|
|
143
|
+
* @example 'worker-1', 'api-server', 'background-processor'
|
|
138
144
|
*/
|
|
139
|
-
id
|
|
145
|
+
id?: string
|
|
140
146
|
|
|
141
147
|
/**
|
|
142
|
-
* Synchronization pattern for fetching jobs.
|
|
143
|
-
*
|
|
144
|
-
* - `'
|
|
145
|
-
* - `'
|
|
146
|
-
* - `
|
|
148
|
+
* Synchronization pattern for fetching jobs from the database.
|
|
149
|
+
*
|
|
150
|
+
* - `'pull'`: Periodically poll the database for new jobs at `pullInterval`
|
|
151
|
+
* - `'push'`: Listen for database notifications when jobs are available (real-time)
|
|
152
|
+
* - `'hybrid'`: Use both pull and push patterns (recommended for reliability)
|
|
153
|
+
* - `false`: Disable automatic job fetching (use `fetch()` manually)
|
|
147
154
|
*
|
|
148
155
|
* @default 'hybrid'
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```typescript
|
|
159
|
+
* // Real-time job processing with fallback polling
|
|
160
|
+
* syncPattern: 'hybrid'
|
|
161
|
+
*
|
|
162
|
+
* // Disable auto-fetching for API-only servers
|
|
163
|
+
* syncPattern: false
|
|
164
|
+
* ```
|
|
149
165
|
*/
|
|
150
|
-
syncPattern
|
|
166
|
+
syncPattern?: 'pull' | 'push' | 'hybrid' | false
|
|
151
167
|
|
|
152
168
|
/**
|
|
153
|
-
* Interval in milliseconds between pull operations when using pull or hybrid sync pattern.
|
|
169
|
+
* Interval in milliseconds between pull operations when using `'pull'` or `'hybrid'` sync pattern.
|
|
170
|
+
* Lower values mean faster job pickup but more database queries.
|
|
154
171
|
*
|
|
155
172
|
* @default 5000
|
|
156
173
|
*/
|
|
157
|
-
pullInterval
|
|
174
|
+
pullInterval?: number
|
|
158
175
|
|
|
159
176
|
/**
|
|
160
|
-
* Maximum number of jobs to fetch in a single batch.
|
|
177
|
+
* Maximum number of jobs to fetch in a single batch from the database.
|
|
178
|
+
* Higher values reduce database round-trips but may increase memory usage.
|
|
161
179
|
*
|
|
162
180
|
* @default 10
|
|
163
181
|
*/
|
|
164
|
-
batchSize
|
|
182
|
+
batchSize?: number
|
|
165
183
|
|
|
166
184
|
/**
|
|
167
185
|
* Maximum number of jobs that can run concurrently per action.
|
|
168
|
-
* This controls the concurrency limit for
|
|
186
|
+
* This controls the concurrency limit for each action's internal queue.
|
|
187
|
+
* Use this to prevent any single action from consuming all resources.
|
|
169
188
|
*
|
|
170
189
|
* @default 100
|
|
171
190
|
*/
|
|
172
|
-
actionConcurrencyLimit
|
|
191
|
+
actionConcurrencyLimit?: number
|
|
173
192
|
|
|
174
193
|
/**
|
|
175
194
|
* Maximum number of jobs that can run concurrently per group key.
|
|
176
195
|
* Jobs with the same group key will respect this limit.
|
|
177
|
-
* This can be overridden using action
|
|
196
|
+
* This is the default value; it can be overridden per-job using `action.groups.concurrency`.
|
|
178
197
|
*
|
|
179
198
|
* @default 10
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```typescript
|
|
202
|
+
* // Limit concurrent jobs per user to 2
|
|
203
|
+
* groupConcurrencyLimit: 2
|
|
204
|
+
* ```
|
|
180
205
|
*/
|
|
181
|
-
groupConcurrencyLimit
|
|
206
|
+
groupConcurrencyLimit?: number
|
|
182
207
|
|
|
183
208
|
/**
|
|
184
209
|
* Whether to run database migrations on startup.
|
|
185
210
|
* When enabled, Duron will automatically apply pending migrations when the adapter starts.
|
|
211
|
+
* Disable this if you manage migrations separately or use a read-only database connection.
|
|
186
212
|
*
|
|
187
213
|
* @default true
|
|
188
214
|
*/
|
|
189
|
-
migrateOnStart
|
|
215
|
+
migrateOnStart?: boolean
|
|
190
216
|
|
|
191
217
|
/**
|
|
192
218
|
* Whether to recover stuck jobs on startup.
|
|
193
219
|
* Stuck jobs are jobs that were marked as active but the process that owned them
|
|
194
|
-
* is no longer running.
|
|
220
|
+
* is no longer running (e.g., after a crash or restart).
|
|
221
|
+
* These jobs will be reset to 'created' status so they can be picked up again.
|
|
195
222
|
*
|
|
196
223
|
* @default true
|
|
197
224
|
*/
|
|
198
|
-
recoverJobsOnStart
|
|
225
|
+
recoverJobsOnStart?: boolean
|
|
199
226
|
|
|
200
227
|
/**
|
|
201
228
|
* Enable multi-process mode for job recovery.
|
|
202
229
|
* When enabled, Duron will ping other processes to check if they're alive
|
|
203
|
-
* before recovering their jobs.
|
|
230
|
+
* before recovering their jobs. This prevents recovering jobs from processes
|
|
231
|
+
* that are still running but slow to respond.
|
|
232
|
+
*
|
|
233
|
+
* Only enable this if you're running multiple Duron instances sharing the same database.
|
|
204
234
|
*
|
|
205
235
|
* @default false
|
|
206
236
|
*/
|
|
207
|
-
multiProcessMode
|
|
237
|
+
multiProcessMode?: boolean
|
|
208
238
|
|
|
209
239
|
/**
|
|
210
240
|
* Timeout in milliseconds to wait for process ping responses in multi-process mode.
|
|
211
241
|
* Processes that don't respond within this timeout will have their jobs recovered.
|
|
242
|
+
* Increase this value if your processes may be temporarily unresponsive under load.
|
|
212
243
|
*
|
|
213
|
-
* @default 5000
|
|
244
|
+
* @default 5000
|
|
214
245
|
*/
|
|
215
|
-
processTimeout
|
|
246
|
+
processTimeout?: number
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const BaseOptionsSchema = z.object({
|
|
250
|
+
id: z.string().optional(),
|
|
251
|
+
syncPattern: z.union([z.literal('pull'), z.literal('push'), z.literal('hybrid'), z.literal(false)]).default('hybrid'),
|
|
252
|
+
pullInterval: z.number().default(5_000),
|
|
253
|
+
batchSize: z.number().default(10),
|
|
254
|
+
actionConcurrencyLimit: z.number().default(100),
|
|
255
|
+
groupConcurrencyLimit: z.number().default(10),
|
|
256
|
+
migrateOnStart: z.boolean().default(true),
|
|
257
|
+
recoverJobsOnStart: z.boolean().default(true),
|
|
258
|
+
multiProcessMode: z.boolean().default(false),
|
|
259
|
+
processTimeout: z.number().default(5 * 1000),
|
|
216
260
|
})
|
|
217
261
|
|
|
262
|
+
// Compile-time check: ensure BaseOptionsInput is assignable to the Zod schema's input type
|
|
263
|
+
type _EnsureBaseOptionsCompatible = BaseOptionsInput extends z.input<typeof BaseOptionsSchema>
|
|
264
|
+
? true
|
|
265
|
+
: 'ERROR: BaseOptionsInput does not match Zod schema input type'
|
|
266
|
+
|
|
267
|
+
declare const _baseOptionsCheck: _EnsureBaseOptionsCompatible
|
|
268
|
+
const _checkOptions: _EnsureBaseOptionsCompatible = true
|
|
269
|
+
|
|
218
270
|
/**
|
|
219
|
-
* Options for configuring a Duron instance.
|
|
271
|
+
* Options for configuring a Duron client instance.
|
|
220
272
|
*
|
|
221
273
|
* @template TActions - Record of action definitions keyed by action name
|
|
222
274
|
* @template TVariables - Type of variables available to actions
|
|
@@ -224,7 +276,7 @@ const BaseOptionsSchema = z.object({
|
|
|
224
276
|
export interface ClientOptions<
|
|
225
277
|
TActions extends Record<string, Action<any, any, TVariables>>,
|
|
226
278
|
TVariables = Record<string, unknown>,
|
|
227
|
-
> extends
|
|
279
|
+
> extends BaseOptionsInput {
|
|
228
280
|
/**
|
|
229
281
|
* The database adapter to use for storing jobs and steps.
|
|
230
282
|
* Required.
|
|
@@ -510,6 +562,7 @@ export class Client<
|
|
|
510
562
|
timeoutMs: action.expire,
|
|
511
563
|
checksum: action.checksum,
|
|
512
564
|
concurrencyLimit,
|
|
565
|
+
concurrencyStepLimit: action.steps.concurrency,
|
|
513
566
|
})
|
|
514
567
|
|
|
515
568
|
if (!jobId) {
|