Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion nodejs/src/cdp/services/job-queue/job-queue-kafka.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,29 @@
import { migrateKafkaCyclotronInvocation } from './job-queue-kafka'
import { DateTime } from 'luxon'

import { deserializeInvocation, migrateKafkaCyclotronInvocation, serializeInvocation } from './job-queue-kafka'

describe('CyclotronJobQueueKafka', () => {
describe('deserializeInvocation', () => {
it.each([
['set', DateTime.utc(2025, 1, 1, 12, 30)],
['unset', undefined],
])('round-trips queueScheduledAt when it is %s', (_, scheduledAt) => {
const json = JSON.stringify(
serializeInvocation({
id: 'invocation-id',
teamId: 1,
functionId: 'function-id',
state: null,
queue: 'hog',
queuePriority: 0,
queueScheduledAt: scheduledAt,
})
)

expect(deserializeInvocation(json).queueScheduledAt?.toISO()).toEqual(scheduledAt?.toISO())
})
})

describe('migrateKafkaCyclotronInvocation', () => {
// Pulled from a real job in kafka
const legacyFormat = {
Expand Down
15 changes: 12 additions & 3 deletions nodejs/src/cdp/services/job-queue/job-queue-kafka.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* To make this easier this class is designed to abstract the queue as much as possible from
* the underlying implementation.
*/
import { DateTime } from 'luxon'
import { Message } from 'node-rdkafka'
import { compress, uncompress } from 'snappy'

Expand Down Expand Up @@ -184,9 +185,7 @@ export class CyclotronJobQueueKafka implements JobQueue {

// Try to decompress, otherwise just use the value as is
const decompressedValue = await uncompress(rawValue).catch(() => rawValue)
const invocation: CyclotronJobInvocation = migrateKafkaCyclotronInvocation(
parseJSON(decompressedValue.toString())
)
const invocation = deserializeInvocation(decompressedValue.toString())

invocation.queueSource = 'kafka' // NOTE: We always set this here, as we know it came from kafka
invocations.push(invocation)
Expand Down Expand Up @@ -248,3 +247,13 @@ export function serializeInvocation(invocation: CyclotronJobInvocation): Cyclotr
queueSource: invocation.queueSource,
}
}

export function deserializeInvocation(json: string): CyclotronJobInvocation {
const invocation = migrateKafkaCyclotronInvocation(parseJSON(json))
// JSON.stringify writes the DateTime as an ISO string, and readers call DateTime methods on it.
const scheduledAt: unknown = invocation.queueScheduledAt
if (typeof scheduledAt === 'string') {
invocation.queueScheduledAt = DateTime.fromISO(scheduledAt, { zone: 'utc' })
}
return invocation
}
Loading