@owlmeans/queue 0.1.18-rc.40 → 0.1.18-rc.42
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/README.md +17 -16
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/queue/SKILL.md +26 -24
- package/agent-meta/skills/scheduled-jobs/SKILL.md +1 -1
- package/build/bridge/types.d.ts +25 -0
- package/build/bridge/types.d.ts.map +1 -0
- package/build/bridge/types.js +2 -0
- package/build/bridge/types.js.map +1 -0
- package/build/bridge.d.ts +5 -28
- package/build/bridge.d.ts.map +1 -1
- package/build/bridge.js +33 -104
- package/build/bridge.js.map +1 -1
- package/build/config.d.ts +6 -22
- package/build/config.d.ts.map +1 -1
- package/build/config.js +10 -92
- package/build/config.js.map +1 -1
- package/build/entrypoint-jobs/types.d.ts +29 -0
- package/build/entrypoint-jobs/types.d.ts.map +1 -0
- package/build/entrypoint-jobs/types.js +2 -0
- package/build/entrypoint-jobs/types.js.map +1 -0
- package/build/entrypoint-jobs.d.ts +5 -0
- package/build/entrypoint-jobs.d.ts.map +1 -0
- package/build/entrypoint-jobs.js +84 -0
- package/build/entrypoint-jobs.js.map +1 -0
- package/build/index.d.ts +8 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -0
- package/build/index.js.map +1 -1
- package/build/protocol/types.d.ts +12 -0
- package/build/protocol/types.d.ts.map +1 -0
- package/build/protocol/types.js +2 -0
- package/build/protocol/types.js.map +1 -0
- package/build/protocol.d.ts +6 -3
- package/build/protocol.d.ts.map +1 -1
- package/build/protocol.js +57 -50
- package/build/protocol.js.map +1 -1
- package/build/queue-config/types.d.ts +29 -0
- package/build/queue-config/types.d.ts.map +1 -0
- package/build/queue-config/types.js +2 -0
- package/build/queue-config/types.js.map +1 -0
- package/build/queue-config.d.ts +9 -0
- package/build/queue-config.d.ts.map +1 -0
- package/build/queue-config.js +83 -0
- package/build/queue-config.js.map +1 -0
- package/build/queue-route/types.d.ts +14 -0
- package/build/queue-route/types.d.ts.map +1 -0
- package/build/queue-route/types.js +2 -0
- package/build/queue-route/types.js.map +1 -0
- package/build/queue-route.d.ts +4 -0
- package/build/queue-route.d.ts.map +1 -0
- package/build/queue-route.js +24 -0
- package/build/queue-route.js.map +1 -0
- package/build/route.d.ts +2 -2
- package/build/route.d.ts.map +1 -1
- package/build/route.js +5 -20
- package/build/route.js.map +1 -1
- package/build/transport.d.ts.map +1 -1
- package/build/transport.js +2 -2
- package/build/transport.js.map +1 -1
- package/build/types.d.ts +3 -0
- package/build/types.d.ts.map +1 -1
- package/build/worker.d.ts +0 -17
- package/build/worker.d.ts.map +1 -1
- package/build/worker.js +1 -36
- package/build/worker.js.map +1 -1
- package/package.json +8 -8
- package/src/bridge/types.ts +25 -0
- package/src/bridge.ts +38 -118
- package/src/config.ts +14 -105
- package/src/entrypoint-jobs/types.ts +29 -0
- package/src/entrypoint-jobs.ts +105 -0
- package/src/index.ts +8 -0
- package/src/protocol/types.ts +16 -0
- package/src/protocol.ts +74 -53
- package/src/queue-config/types.ts +29 -0
- package/src/queue-config.ts +102 -0
- package/src/queue-route/types.ts +14 -0
- package/src/queue-route.ts +33 -0
- package/src/route.ts +6 -23
- package/src/transport.ts +3 -3
- package/src/types.ts +3 -0
- package/src/worker.ts +2 -48
- package/tests/bridge.spec.ts +8 -8
- package/tests/config.spec.ts +11 -10
- package/tests/protocol.spec.ts +6 -6
- package/tests/schedule.spec.ts +13 -14
- package/build/types.local.d.ts +0 -3
- package/build/types.local.d.ts.map +0 -1
- package/build/types.local.js +0 -2
- package/build/types.local.js.map +0 -1
- package/src/types.local.ts +0 -3
package/src/route.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { backend, type RouteDeclaration, type RouteModel, type RouteOptions } from '@owlmeans/route'
|
|
2
|
-
import { UnknownQueue } from './errors.js'
|
|
3
2
|
import { QUEUE_PROTOCOL } from './consts.js'
|
|
4
3
|
import type { QueueRouteOptions } from './types.js'
|
|
4
|
+
import { queueRouteHelper } from './queue-route.js'
|
|
5
5
|
|
|
6
6
|
/** Declare a backend route carried by a queue. */
|
|
7
7
|
export const job = (
|
|
@@ -15,26 +15,9 @@ export const job = (
|
|
|
15
15
|
return declaration
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
export const isQueueRoute = (route: RouteDeclaration | RouteModel): boolean =>
|
|
20
|
-
('route' in route ? route.route : route).protocol === QUEUE_PROTOCOL
|
|
18
|
+
/** @deprecated compat:factory-refactor — use `queueRouteHelper.isQueueRoute(…)` */
|
|
19
|
+
export const isQueueRoute = (route: RouteDeclaration | RouteModel): boolean => queueRouteHelper.isQueueRoute(route)
|
|
21
20
|
|
|
22
|
-
/**
|
|
23
|
-
export const queueRouteOptions = (
|
|
24
|
-
route
|
|
25
|
-
): Pick<QueueRouteOptions, 'queue' | 'reply'> => {
|
|
26
|
-
const declaration = 'route' in route ? route.route : route
|
|
27
|
-
if (declaration.protocol !== QUEUE_PROTOCOL
|
|
28
|
-
|| declaration.protocolOptions == null
|
|
29
|
-
|| typeof declaration.protocolOptions !== 'object') {
|
|
30
|
-
throw new UnknownQueue(`${declaration.alias}: not a queue protocol`)
|
|
31
|
-
}
|
|
32
|
-
const options = declaration.protocolOptions as Record<string, unknown>
|
|
33
|
-
if (typeof options.queue !== 'string' || options.queue.trim() === '') {
|
|
34
|
-
throw new UnknownQueue(`${declaration.alias}: route declares no queue`)
|
|
35
|
-
}
|
|
36
|
-
if (options.reply != null && typeof options.reply !== 'boolean') {
|
|
37
|
-
throw new UnknownQueue(`${declaration.alias}: invalid queue reply option`)
|
|
38
|
-
}
|
|
39
|
-
return { queue: options.queue, reply: options.reply as boolean | undefined }
|
|
40
|
-
}
|
|
21
|
+
/** @deprecated compat:factory-refactor — use `queueRouteHelper.queueRouteOptions(…)` */
|
|
22
|
+
export const queueRouteOptions = (route: RouteDeclaration | RouteModel): Pick<QueueRouteOptions, 'queue' | 'reply'> =>
|
|
23
|
+
queueRouteHelper.queueRouteOptions(route)
|
package/src/transport.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { type AbstractRequest, type AbstractResponse, type EntrypointTransport,
|
|
|
3
3
|
import { ResilientError } from '@owlmeans/error'
|
|
4
4
|
import type { Config, Context, JobEnvelope, JobReply, QueueAppend } from './types.js'
|
|
5
5
|
import { DEFAULT_JOB_TIMEOUT, QUEUE_PROTOCOL } from './consts.js'
|
|
6
|
-
import {
|
|
6
|
+
import { queueRouteHelper } from './queue-route.js'
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* The producing half of the bridge: it turns a call on a QUEUE entrypoint into a job, and the
|
|
@@ -15,7 +15,7 @@ import { queueRouteOptions } from './route.js'
|
|
|
15
15
|
* the request rather than from the entrypoint: the far side rebuilds a request, and anything only
|
|
16
16
|
* HTTP understands would not survive the trip anyway.
|
|
17
17
|
*/
|
|
18
|
-
export const makeQueueTransport = (alias: string = transportAlias(QUEUE_PROTOCOL)) => {
|
|
18
|
+
export const makeQueueTransport = (alias: string = transportAlias(QUEUE_PROTOCOL)): EntrypointTransport => {
|
|
19
19
|
const location = `queue-transport:${alias}`
|
|
20
20
|
|
|
21
21
|
const service = createService<EntrypointTransport>(alias, {
|
|
@@ -26,7 +26,7 @@ export const makeQueueTransport = (alias: string = transportAlias(QUEUE_PROTOCOL
|
|
|
26
26
|
const entrypoint = context.entrypoint<CommonEntrypoint>(req.alias)
|
|
27
27
|
const route = entrypoint.route.route
|
|
28
28
|
|
|
29
|
-
const { queue, reply: waitsForReply } = queueRouteOptions(route)
|
|
29
|
+
const { queue, reply: waitsForReply } = queueRouteHelper.queueRouteOptions(route)
|
|
30
30
|
|
|
31
31
|
const jobs = (context as unknown as QueueAppend).jobs<JobEnvelope, JobReply<T>>(queue)
|
|
32
32
|
|
package/src/types.ts
CHANGED
|
@@ -321,3 +321,6 @@ export interface QueueRouteOptions extends Omit<RouteOptions, 'protocol' | 'prot
|
|
|
321
321
|
queue: string
|
|
322
322
|
reply?: boolean
|
|
323
323
|
}
|
|
324
|
+
|
|
325
|
+
/** The context the queue protocol helper is bound to: an app context with the queue appended. */
|
|
326
|
+
export interface QueueContext extends Context<Config>, QueueAppend {}
|
package/src/worker.ts
CHANGED
|
@@ -1,53 +1,7 @@
|
|
|
1
1
|
import type { Middleware } from '@owlmeans/context'
|
|
2
|
-
import { MiddlewareStage, MiddlewareType
|
|
3
|
-
import type {
|
|
4
|
-
import type { Config, Context, JobContext, JobEnvelope, JobProcessor, QueueWorkerService } from './types.js'
|
|
5
|
-
import { handleJob } from './bridge.js'
|
|
2
|
+
import { MiddlewareStage, MiddlewareType } from '@owlmeans/context'
|
|
3
|
+
import type { Config, Context, QueueWorkerService } from './types.js'
|
|
6
4
|
import { DEFAULT_ALIAS } from './consts.js'
|
|
7
|
-
import { isQueueRoute, queueRouteOptions } from './route.js'
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Every queued entrypoint this process both SERVES and LISTENS to, grouped by queue.
|
|
11
|
-
*
|
|
12
|
-
* Both halves are required and they answer different questions. Serving is about code — the alias
|
|
13
|
-
* was bound here, so a handler exists. Listening is about deployment — this process was
|
|
14
|
-
* configured to consume that queue. A worker that bound queues by what it can serve would make
|
|
15
|
-
* every deployment of the same binary a worker for everything it happens to import.
|
|
16
|
-
*/
|
|
17
|
-
export const servedJobs = <C extends Config, T extends Context<C>>(
|
|
18
|
-
context: T
|
|
19
|
-
): Map<string, CommonEntrypoint[]> => {
|
|
20
|
-
const listen = context.cfg.queue?.listen ?? []
|
|
21
|
-
const served = new Map<string, CommonEntrypoint[]>()
|
|
22
|
-
|
|
23
|
-
context.entrypoints<CommonEntrypoint>().forEach(entrypoint => {
|
|
24
|
-
const route = entrypoint.route.route
|
|
25
|
-
if (route.type !== AppType.Backend || !isQueueRoute(route)) {
|
|
26
|
-
return
|
|
27
|
-
}
|
|
28
|
-
if (route.service != null && route.service !== context.cfg.service) {
|
|
29
|
-
return
|
|
30
|
-
}
|
|
31
|
-
const { queue } = queueRouteOptions(route)
|
|
32
|
-
if (entrypoint.handle == null || !listen.includes(queue)) {
|
|
33
|
-
return
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
served.set(queue, [...(served.get(queue) ?? []), entrypoint])
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
return served
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* A processor that runs a queued entrypoint call. The driver dispatches by job name, and an
|
|
44
|
-
* entrypoint job's name IS its alias — which is what lets one worker carry both entrypoint jobs
|
|
45
|
-
* and the internal steps an application registers with `process()`.
|
|
46
|
-
*/
|
|
47
|
-
export const entrypointProcessor = <C extends Config, T extends Context<C>>(
|
|
48
|
-
context: T
|
|
49
|
-
): JobProcessor<JobEnvelope, unknown> =>
|
|
50
|
-
async (job: JobContext<JobEnvelope>) => await handleJob(context, job)
|
|
51
5
|
|
|
52
6
|
/**
|
|
53
7
|
* Start the worker once the context is ready.
|
package/tests/bridge.spec.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, test, expect } from 'bun:test'
|
|
2
|
-
import {
|
|
2
|
+
import { queueBridgeHelper } from '../src/bridge.js'
|
|
3
3
|
import { EnvelopeExpired } from '../src/errors.js'
|
|
4
4
|
import type { JobEnvelope } from '../src/types.js'
|
|
5
5
|
|
|
@@ -9,7 +9,7 @@ const envelope = (enqueuedAt?: string): JobEnvelope => ({
|
|
|
9
9
|
|
|
10
10
|
describe('rebuilding the request', () => {
|
|
11
11
|
test('the envelope becomes an ordinary request', () => {
|
|
12
|
-
const request = requestOf(envelope(), '/story/:id/code')
|
|
12
|
+
const request = queueBridgeHelper.requestOf(envelope(), '/story/:id/code')
|
|
13
13
|
|
|
14
14
|
expect(request.alias).toBe('story:code')
|
|
15
15
|
expect(request.params).toEqual({ id: '7' })
|
|
@@ -22,7 +22,7 @@ describe('rebuilding the request', () => {
|
|
|
22
22
|
* checking, so they have to arrive as empty containers rather than as undefined.
|
|
23
23
|
*/
|
|
24
24
|
test('absent parts arrive as empty, never undefined', () => {
|
|
25
|
-
const request = requestOf({ alias: 'story:code' }, '/x')
|
|
25
|
+
const request = queueBridgeHelper.requestOf({ alias: 'story:code' }, '/x')
|
|
26
26
|
|
|
27
27
|
expect(request.params).toEqual({})
|
|
28
28
|
expect(request.headers).toEqual({})
|
|
@@ -32,13 +32,13 @@ describe('rebuilding the request', () => {
|
|
|
32
32
|
|
|
33
33
|
describe('envelope freshness', () => {
|
|
34
34
|
test('a fresh envelope passes', () => {
|
|
35
|
-
expect(() => assertFresh(envelope(new Date().toISOString()), 60)).not.toThrow()
|
|
35
|
+
expect(() => queueBridgeHelper.assertFresh(envelope(new Date().toISOString()), 60)).not.toThrow()
|
|
36
36
|
})
|
|
37
37
|
|
|
38
38
|
test('an envelope older than the window is refused', () => {
|
|
39
39
|
const old = new Date(Date.now() - 120_000).toISOString()
|
|
40
40
|
|
|
41
|
-
expect(() => assertFresh(envelope(old), 60)).toThrow(EnvelopeExpired)
|
|
41
|
+
expect(() => queueBridgeHelper.assertFresh(envelope(old), 60)).toThrow(EnvelopeExpired)
|
|
42
42
|
})
|
|
43
43
|
|
|
44
44
|
/**
|
|
@@ -49,16 +49,16 @@ describe('envelope freshness', () => {
|
|
|
49
49
|
test('a long wait in the queue is not what expiry is for', () => {
|
|
50
50
|
const enqueued = new Date(Date.now() - 3600_000).toISOString()
|
|
51
51
|
|
|
52
|
-
expect(() => assertFresh(envelope(enqueued), 86_400)).not.toThrow()
|
|
52
|
+
expect(() => queueBridgeHelper.assertFresh(envelope(enqueued), 86_400)).not.toThrow()
|
|
53
53
|
})
|
|
54
54
|
|
|
55
55
|
test('no configured window means no check', () => {
|
|
56
56
|
const ancient = new Date(0).toISOString()
|
|
57
57
|
|
|
58
|
-
expect(() => assertFresh(envelope(ancient), undefined)).not.toThrow()
|
|
58
|
+
expect(() => queueBridgeHelper.assertFresh(envelope(ancient), undefined)).not.toThrow()
|
|
59
59
|
})
|
|
60
60
|
|
|
61
61
|
test('an envelope without a timestamp is not judged', () => {
|
|
62
|
-
expect(() => assertFresh(envelope(undefined), 60)).not.toThrow()
|
|
62
|
+
expect(() => queueBridgeHelper.assertFresh(envelope(undefined), 60)).not.toThrow()
|
|
63
63
|
})
|
|
64
64
|
})
|
package/tests/config.spec.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, test, expect } from 'bun:test'
|
|
2
|
-
import { declareQueue,
|
|
2
|
+
import { declareQueue, listenQueues } from '../src/config.js'
|
|
3
|
+
import { queueConfigOf } from '../src/queue-config.js'
|
|
3
4
|
import { UnknownQueue } from '../src/errors.js'
|
|
4
5
|
import type { Config } from '../src/types.js'
|
|
5
6
|
|
|
@@ -9,7 +10,7 @@ describe('declaring queues', () => {
|
|
|
9
10
|
test('a declaration records the queue and the jobs it accepts', () => {
|
|
10
11
|
const config = declareQueue(cfg(), 'work', ['story:code', 'story:gate'])
|
|
11
12
|
|
|
12
|
-
expect(queueOf(
|
|
13
|
+
expect(queueConfigOf(config).queueOf('work').jobs).toEqual(['story:code', 'story:gate'])
|
|
13
14
|
})
|
|
14
15
|
|
|
15
16
|
/**
|
|
@@ -22,18 +23,18 @@ describe('declaring queues', () => {
|
|
|
22
23
|
config = declareQueue(config, 'work', ['story:code', 'story:gate'])
|
|
23
24
|
|
|
24
25
|
expect(config.queue?.queues).toHaveLength(1)
|
|
25
|
-
expect(queueOf(
|
|
26
|
+
expect(queueConfigOf(config).queueOf('work').jobs).toHaveLength(2)
|
|
26
27
|
})
|
|
27
28
|
|
|
28
29
|
test('asking for a queue nobody declared is an error, not undefined', () => {
|
|
29
|
-
expect(() =>
|
|
30
|
+
expect(() => queueConfigOf(cfg()).queueOf('missing')).toThrow(UnknownQueue)
|
|
30
31
|
})
|
|
31
32
|
|
|
32
33
|
test('a job name resolves back to the queue that accepts it', () => {
|
|
33
34
|
const config = declareQueue(declareQueue(cfg(), 'work', ['story:code']), 'ops', ['files:get'])
|
|
34
35
|
|
|
35
|
-
expect(queueOfJob(
|
|
36
|
-
expect(queueOfJob(
|
|
36
|
+
expect(queueConfigOf(config).queueOfJob('files:get')?.name).toBe('ops')
|
|
37
|
+
expect(queueConfigOf(config).queueOfJob('nothing:declared')).toBeUndefined()
|
|
37
38
|
})
|
|
38
39
|
})
|
|
39
40
|
|
|
@@ -45,7 +46,7 @@ describe('listening', () => {
|
|
|
45
46
|
test('declaring a queue does not make the process listen to it', () => {
|
|
46
47
|
const config = declareQueue(cfg(), 'work', ['story:code'])
|
|
47
48
|
|
|
48
|
-
expect(isListening(
|
|
49
|
+
expect(queueConfigOf(config).isListening('work')).toBe(false)
|
|
49
50
|
expect(config.queue?.listen ?? []).toHaveLength(0)
|
|
50
51
|
})
|
|
51
52
|
|
|
@@ -54,13 +55,13 @@ describe('listening', () => {
|
|
|
54
55
|
config = listenQueues(config, 'work', 'ops')
|
|
55
56
|
|
|
56
57
|
expect(config.queue?.listen).toEqual(['work', 'ops'])
|
|
57
|
-
expect(isListening(
|
|
58
|
+
expect(queueConfigOf(config).isListening('ops')).toBe(true)
|
|
58
59
|
})
|
|
59
60
|
|
|
60
61
|
test('listening and declaring do not overwrite each other', () => {
|
|
61
62
|
const config = declareQueue(listenQueues(cfg(), 'work'), 'work', ['story:code'])
|
|
62
63
|
|
|
63
|
-
expect(isListening(
|
|
64
|
-
expect(queueOf(
|
|
64
|
+
expect(queueConfigOf(config).isListening('work')).toBe(true)
|
|
65
|
+
expect(queueConfigOf(config).queueOf('work').jobs).toEqual(['story:code'])
|
|
65
66
|
})
|
|
66
67
|
})
|
package/tests/protocol.spec.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { describe, expect, test } from 'bun:test'
|
|
|
2
2
|
import { contract, protocol, schema } from '@owlmeans/entrypoint'
|
|
3
3
|
import { route } from '@owlmeans/route'
|
|
4
4
|
import type { JSONSchemaType } from 'ajv'
|
|
5
|
-
import {
|
|
5
|
+
import { job, queueProtocolOf, type JobRecord } from '../src/index.js'
|
|
6
6
|
|
|
7
7
|
interface Input { value: number }
|
|
8
8
|
interface Output { doubled: number }
|
|
@@ -35,23 +35,23 @@ const context = (reply: unknown = { value: { doubled: 6 } }) => {
|
|
|
35
35
|
describe('protocol-aware queue calls', () => {
|
|
36
36
|
test('derives the broker address and keeps per-call options', async () => {
|
|
37
37
|
const ctx = context()
|
|
38
|
-
const queued = await
|
|
38
|
+
const queued = await queueProtocolOf(ctx as never).enqueue(declaration, { body: { value: 3 } }, {
|
|
39
39
|
delay: 250, attempts: 3, id: 'projection-1',
|
|
40
40
|
})
|
|
41
41
|
expect(queued.queue).toBe('test')
|
|
42
42
|
expect(ctx.created[0]?.name).toBe(declaration.alias)
|
|
43
43
|
expect(ctx.created[0]?.opts).toEqual({ delay: 250, attempts: 3, id: 'projection-1' })
|
|
44
|
-
expect(await
|
|
44
|
+
expect(await queueProtocolOf(ctx as never).waitFor(declaration, queued as never)).toEqual({ doubled: 6 })
|
|
45
45
|
})
|
|
46
46
|
|
|
47
47
|
test('rejects raw aliases and non-queue declarations at runtime', async () => {
|
|
48
|
-
await expect(
|
|
48
|
+
await expect(queueProtocolOf(context() as never).enqueue(declaration.alias as never, {} as never)).rejects.toThrow()
|
|
49
49
|
const http = protocol(route('test:http', '/http'), contract())
|
|
50
|
-
await expect(
|
|
50
|
+
await expect(queueProtocolOf(context() as never).enqueue(http, {})).rejects.toThrow()
|
|
51
51
|
})
|
|
52
52
|
|
|
53
53
|
test('rejects a job from another queue or protocol', async () => {
|
|
54
|
-
await expect(
|
|
54
|
+
await expect(queueProtocolOf(context() as never).waitFor(declaration, {
|
|
55
55
|
id: 'x', queue: 'other', name: declaration.alias, data: {},
|
|
56
56
|
} as never)).rejects.toThrow()
|
|
57
57
|
})
|
package/tests/schedule.spec.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { describe, test, expect } from 'bun:test'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
} from '../src/config.js'
|
|
2
|
+
import { declareQueue, declareSchedule } from '../src/config.js'
|
|
3
|
+
import { queueConfigOf } from '../src/queue-config.js'
|
|
5
4
|
import { ScheduleMisdeclared, UnknownJobName, UnknownQueue } from '../src/errors.js'
|
|
6
5
|
import type { Config, ScheduleDeclaration } from '../src/types.js'
|
|
7
6
|
|
|
@@ -16,23 +15,23 @@ const nightly: ScheduleDeclaration = {
|
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
const misdeclared = (schedule: Partial<ScheduleDeclaration>): () => void =>
|
|
19
|
-
() =>
|
|
18
|
+
() => queueConfigOf(cfg()).assertSchedule({ ...nightly, ...schedule } as ScheduleDeclaration)
|
|
20
19
|
|
|
21
20
|
describe('declaring schedules', () => {
|
|
22
21
|
test('a declaration is recorded and read back by its queue', () => {
|
|
23
22
|
const config = declareSchedule(cfg(), nightly)
|
|
24
23
|
|
|
25
|
-
expect(schedulesOf(
|
|
26
|
-
expect(schedulesOf(
|
|
27
|
-
expect(
|
|
24
|
+
expect(queueConfigOf(config).schedulesOf('maintenance')).toEqual([nightly])
|
|
25
|
+
expect(queueConfigOf(config).schedulesOf('work')).toEqual([])
|
|
26
|
+
expect(queueConfigOf(config).schedulesOf()).toHaveLength(1)
|
|
28
27
|
})
|
|
29
28
|
|
|
30
29
|
test('re-declaring an id replaces rather than appends', () => {
|
|
31
30
|
let config = declareSchedule(cfg(), nightly)
|
|
32
31
|
config = declareSchedule(config, { ...nightly, pattern: '0 4 * * *' })
|
|
33
32
|
|
|
34
|
-
expect(
|
|
35
|
-
expect(
|
|
33
|
+
expect(queueConfigOf(config).schedulesOf()).toHaveLength(1)
|
|
34
|
+
expect(queueConfigOf(config).schedulesOf()[0].pattern).toBe('0 4 * * *')
|
|
36
35
|
})
|
|
37
36
|
|
|
38
37
|
/**
|
|
@@ -44,14 +43,14 @@ describe('declaring schedules', () => {
|
|
|
44
43
|
|
|
45
44
|
expect(() => declareSchedule(config, { ...nightly, queue: 'missing' })).toThrow(UnknownQueue)
|
|
46
45
|
expect(() => declareSchedule(config, { ...nightly, name: 'story:code' })).toThrow(UnknownJobName)
|
|
47
|
-
expect(
|
|
46
|
+
expect(queueConfigOf(config).schedulesOf()).toHaveLength(0)
|
|
48
47
|
})
|
|
49
48
|
|
|
50
49
|
test('re-declaring the queue keeps its schedules', () => {
|
|
51
50
|
const config = declareQueue(declareSchedule(cfg(), nightly), 'maintenance', ['reconcile'])
|
|
52
51
|
|
|
53
|
-
expect(queueOf(
|
|
54
|
-
expect(
|
|
52
|
+
expect(queueConfigOf(config).queueOf('maintenance').jobs).toEqual(['reconcile'])
|
|
53
|
+
expect(queueConfigOf(config).schedulesOf()).toEqual([nightly])
|
|
55
54
|
})
|
|
56
55
|
})
|
|
57
56
|
|
|
@@ -87,7 +86,7 @@ describe('asserting every schedule', () => {
|
|
|
87
86
|
const config = declareSchedule(cfg(), nightly)
|
|
88
87
|
config.queue?.schedules?.push({ ...nightly, pattern: '0 5 * * *' })
|
|
89
88
|
|
|
90
|
-
expect(() =>
|
|
89
|
+
expect(() => queueConfigOf(config).assertSchedules()).toThrow(/duplicate/)
|
|
91
90
|
})
|
|
92
91
|
|
|
93
92
|
/** The configuration is plain data; a schedule written into it directly is checked too. */
|
|
@@ -95,6 +94,6 @@ describe('asserting every schedule', () => {
|
|
|
95
94
|
const config = declareSchedule(cfg(), nightly)
|
|
96
95
|
config.queue?.schedules?.push({ id: 'orphan', queue: 'maintenance', name: 'gone', every: 1_000 })
|
|
97
96
|
|
|
98
|
-
expect(() =>
|
|
97
|
+
expect(() => queueConfigOf(config).assertSchedules()).toThrow(UnknownJobName)
|
|
99
98
|
})
|
|
100
99
|
})
|
package/build/types.local.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.local.d.ts","sourceRoot":"","sources":["../src/types.local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE9D,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,WAAW,CAAA"}
|
package/build/types.local.js
DELETED
package/build/types.local.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.local.js","sourceRoot":"","sources":["../src/types.local.ts"],"names":[],"mappings":""}
|
package/src/types.local.ts
DELETED