Skip to content

Commit

Permalink
fix(flow): parent job cannot be replaced (python) (#2417)
Browse files Browse the repository at this point in the history
  • Loading branch information
roggervalf authored Feb 13, 2024
1 parent f2e11b4 commit 2696ef8
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 34 deletions.
1 change: 1 addition & 0 deletions python/bullmq/error_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ class ErrorCode(Enum):
JobPendingDependencies = -4
ParentJobNotExist = -5
JobLockMismatch = -6
ParentJobCannotBeReplaced = -7
2 changes: 2 additions & 0 deletions python/bullmq/scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,8 @@ def finishedErrors(self, code: int, jobId: str, command: str, state: str) -> Typ
return TypeError(f"Missing key for parent job {jobId}.{command}")
elif code == ErrorCode.JobLockMismatch.value:
return TypeError(f"Lock mismatch for job {jobId}. Cmd {command} from {state}")
elif code == ErrorCode.ParentJobCannotBeReplaced.value:
return TypeError(f"The parent job of job {jobId} cannot be replaced. {command}")
else:
return TypeError(f"Unknown code {str(code)} error for {jobId}.{command}")

Expand Down
4 changes: 4 additions & 0 deletions src/classes/scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,10 @@ export class Scripts {
return new Error(
`Lock mismatch for job ${jobId}. Cmd ${command} from ${state}`,
);
case ErrorCode.ParentJobCannotBeReplaced:
return new Error(
`The parent job of job ${jobId} cannot be replaced. ${command}`,
);
default:
return new Error(`Unknown code ${code} error for ${jobId}. ${command}`);
}
Expand Down
12 changes: 4 additions & 8 deletions src/commands/addDelayedJob-6.lua
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ local parentData
-- Includes
--- @include "includes/addDelayMarkerIfNeeded"
--- @include "includes/getOrSetMaxEvents"
--- @include "includes/handleDuplicatedJob"
--- @include "includes/isQueuePaused"
--- @include "includes/storeJob"
--- @include "includes/updateExistingJobsParent"
Expand All @@ -77,17 +78,12 @@ if args[2] == "" then
jobId = jobCounter
jobIdKey = args[1] .. jobId
else
-- Refactor to: handleDuplicateJob.lua
jobId = args[2]
jobIdKey = args[1] .. jobId
if rcall("EXISTS", jobIdKey) == 1 then
updateExistingJobsParent(parentKey, parent, parentData,
parentDependenciesKey, completedKey, jobIdKey,
jobId, timestamp)
rcall("XADD", eventsKey, "MAXLEN", "~", maxEvents, "*", "event",
"duplicated", "jobId", jobId)

return jobId .. "" -- convert to string
return handleDuplicatedJob(jobIdKey, jobId, parentKey, parent,
parentData, parentDependenciesKey, completedKey, eventsKey,
maxEvents, timestamp)
end
end

Expand Down
13 changes: 5 additions & 8 deletions src/commands/addParentJob-4.lua
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ local parent = args[8]
local parentData

-- Includes
--- @include "includes/getOrSetMaxEvents"
--- @include "includes/handleDuplicatedJob"
--- @include "includes/storeJob"
--- @include "includes/updateExistingJobsParent"
--- @include "includes/getOrSetMaxEvents"

if parentKey ~= nil then
if rcall("EXISTS", parentKey) ~= 1 then return -5 end
Expand All @@ -72,13 +73,9 @@ else
jobId = args[2]
jobIdKey = args[1] .. jobId
if rcall("EXISTS", jobIdKey) == 1 then
updateExistingJobsParent(parentKey, parent, parentData,
parentDependenciesKey, completedKey, jobIdKey,
jobId, timestamp)
rcall("XADD", eventsKey, "MAXLEN", "~", maxEvents, "*", "event",
"duplicated", "jobId", jobId)

return jobId .. "" -- convert to string
return handleDuplicatedJob(jobIdKey, jobId, parentKey, parent,
parentData, parentDependenciesKey, completedKey, eventsKey,
maxEvents, timestamp)
end
end

Expand Down
16 changes: 6 additions & 10 deletions src/commands/addPrioritizedJob-7.lua
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,12 @@ local parent = args[8]
local parentData

-- Includes
--- @include "includes/addJobWithPriority"
--- @include "includes/storeJob"
--- @include "includes/getOrSetMaxEvents"
--- @include "includes/handleDuplicatedJob"
--- @include "includes/isQueuePaused"
--- @include "includes/addJobWithPriority"
--- @include "includes/updateExistingJobsParent"
--- @include "includes/getOrSetMaxEvents"

if parentKey ~= nil then
if rcall("EXISTS", parentKey) ~= 1 then return -5 end
Expand All @@ -79,14 +80,9 @@ else
jobId = args[2]
jobIdKey = args[1] .. jobId
if rcall("EXISTS", jobIdKey) == 1 then
updateExistingJobsParent(parentKey, parent, parentData,
parentDependenciesKey, completedKey, jobIdKey,
jobId, timestamp)

rcall("XADD", eventsKey, "MAXLEN", "~", maxEvents, "*", "event",
"duplicated", "jobId", jobId)

return jobId .. "" -- convert to string
return handleDuplicatedJob(jobIdKey, jobId, parentKey, parent,
parentData, parentDependenciesKey, completedKey, eventsKey,
maxEvents, timestamp)
end
end

Expand Down
12 changes: 4 additions & 8 deletions src/commands/addStandardJob-7.lua
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ local parentData
--- @include "includes/addJobInTargetList"
--- @include "includes/getOrSetMaxEvents"
--- @include "includes/getTargetQueueList"
--- @include "includes/handleDuplicatedJob"
--- @include "includes/storeJob"
--- @include "includes/updateExistingJobsParent"

Expand All @@ -84,14 +85,9 @@ else
jobId = args[2]
jobIdKey = args[1] .. jobId
if rcall("EXISTS", jobIdKey) == 1 then
updateExistingJobsParent(parentKey, parent, parentData,
parentDependenciesKey, KEYS[5], jobIdKey,
jobId, timestamp)

rcall("XADD", eventsKey, "MAXLEN", "~", maxEvents, "*", "event",
"duplicated", "jobId", jobId)

return jobId .. "" -- convert to string
return handleDuplicatedJob(jobIdKey, jobId, parentKey, parent,
parentData, parentDependenciesKey, KEYS[5], eventsKey,
maxEvents, timestamp)
end
end

Expand Down
26 changes: 26 additions & 0 deletions src/commands/includes/handleDuplicatedJob.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--[[
Function to handle the case when job is duplicated.
]]

-- Includes
--- @include "updateExistingJobsParent"

local function handleDuplicatedJob(jobKey, jobId, currentParentKey, currentParent,
parentData, parentDependenciesKey, completedKey, eventsKey, maxEvents, timestamp)
local existedParentKey = rcall("HGET", jobKey, "parentKey")

if not existedParentKey then
updateExistingJobsParent(currentParentKey, currentParent, parentData,
parentDependenciesKey, completedKey, jobKey,
jobId, timestamp)
else
if currentParentKey ~= nil and currentParentKey ~= existedParentKey
and (rcall("EXISTS", existedParentKey) == 1) then
return -7
end
end
rcall("XADD", eventsKey, "MAXLEN", "~", maxEvents, "*", "event",
"duplicated", "jobId", jobId)

return jobId .. "" -- convert to string
end
1 change: 1 addition & 0 deletions src/enums/error-code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export enum ErrorCode {
JobPendingDependencies = -4,
ParentJobNotExist = -5,
JobLockMismatch = -6,
ParentJobCannotBeReplaced = -7,
}
48 changes: 48 additions & 0 deletions tests/test_flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1318,6 +1318,54 @@ describe('flows', () => {
await worker.close();
await flow.close();
});

describe('when job already have a parent', async () => {
it('throws an error', async () => {
const flow = new FlowProducer({ connection, prefix });
await flow.add({
queueName,
name: 'tue',
opts: {
jobId: 'tue',
},
children: [
{
name: 'mon',
queueName,
opts: {
jobId: 'mon',
},
},
],
});

await queue.add(
'wed',
{},
{
jobId: 'wed',
},
);

await expect(
queue.add(
'mon',
{},
{
jobId: 'mon',
parent: {
id: 'wed',
queue: `${prefix}:${queueName}`,
},
},
),
).to.be.rejectedWith(
`The parent job of job ${prefix}:${queueName}:wed cannot be replaced. addJob`,
);

await flow.close();
});
});
});

describe('when custom prefix is set in flow producer', async () => {
Expand Down

0 comments on commit 2696ef8

Please sign in to comment.