Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(repeatable): new repeatables structure #2617

Merged
merged 10 commits into from
Jul 16, 2024
Merged

Conversation

roggervalf
Copy link
Collaborator

@roggervalf roggervalf commented Jun 22, 2024

ref #2612 fixes #2399 #2596

table.insert(optionalValues, opts['every'])
end

rcall("HMSET", repeatKey .. ":" .. customKey, "name", opts['name'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to use a HMSET here? wondering if we just could store directly the msg pack data in a normal Redis key 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure, but I feel more natural to use a hmset if the intention is also to update those options or if we need to get specific values from it without getting all attributes

return customKey
end

if ARGV[4] == '0' then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this check needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as one of my comments above, worker checks existence to know if it needs to add a new delayed job while queue.add just adds repeatables whithout this check. That's my understanding from the actual logic

@@ -31,7 +36,7 @@ export class Repeat extends QueueBase {
skipCheckExists?: boolean,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you remember the use case where this boolean was needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was inspecting the code and here is false by default https://github.com/taskforcesh/bullmq/blob/master/src/classes/worker.ts#L721 in worker class (check the existence in case we need to stop adding the next delayed job), here is true https://github.com/taskforcesh/bullmq/blob/master/src/classes/queue.ts#L209 (where we are not checking the existence of that repeatable job and we add the repeatable job)

@@ -70,23 +75,28 @@ export class Repeat extends QueueBase {
repeatOpts.jobId = opts.jobId;
}

const repeatJobKey = getRepeatKey(name, repeatOpts);
const optionsConcat = getRepeatKey(name, repeatOpts);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should rename the function getRepeatKey if this is not going to be the key anymore.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good, what about getQualifiedName

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it is returning a concatenation of options, maybe getRepeatCocatOptions ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good

//
// Generate unique job id for this iteration.
//
const jobId = this.getRepeatJobId({
name,
const jobId = this.getRepeatDelayedJobId({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is important that this jobId is generated in the same way as in the previous version to avoid breaking changes.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it won't be a breaking change in this case as the jobId is only used for new delayed jobs and set it once. Also when removing old cron jobs I'm considering checking the old format before the new one

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the edge case if it adds a delayed job with a different jobId but the same delay time, then you will end up having 2 reputable jobs at least in one iteration, but maybe this edge case cannot happen in practice.

const repeatJobId = this.getRepeatJobId({
const optionsConcat = getRepeatKey(name, { ...repeat, jobId });
const repeatJobKey = repeat.key ?? this.hash(optionsConcat);
const oldRepeatJobId = this.getRepeatJobId({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the word "legacy" instead of "old" makes this more explicit.

@@ -1,9 +1,10 @@
export type RepeatableJob = {
key: string;
name: string;
id: string | null;
id?: string | null;
Copy link
Collaborator Author

@roggervalf roggervalf Jun 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jobId is not a useful attribute now that we can pass a custom key, in new repeatable jobs this value won't be used

table.insert(optionalValues, opts['every'])
end

rcall("HMSET", repeatKey .. ":" .. customKey, "name", opts['name'],
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure, but I feel more natural to use a hmset if the intention is also to update those options or if we need to get specific values from it without getting all attributes

@@ -31,7 +36,7 @@ export class Repeat extends QueueBase {
skipCheckExists?: boolean,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was inspecting the code and here is false by default https://github.com/taskforcesh/bullmq/blob/master/src/classes/worker.ts#L721 in worker class (check the existence in case we need to stop adding the next delayed job), here is true https://github.com/taskforcesh/bullmq/blob/master/src/classes/queue.ts#L209 (where we are not checking the existence of that repeatable job and we add the repeatable job)

@@ -70,23 +75,28 @@ export class Repeat extends QueueBase {
repeatOpts.jobId = opts.jobId;
}

const repeatJobKey = getRepeatKey(name, repeatOpts);
const optionsConcat = getRepeatKey(name, repeatOpts);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good, what about getQualifiedName

//
// Generate unique job id for this iteration.
//
const jobId = this.getRepeatJobId({
name,
const jobId = this.getRepeatDelayedJobId({
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it won't be a breaking change in this case as the jobId is only used for new delayed jobs and set it once. Also when removing old cron jobs I'm considering checking the old format before the new one

return customKey
end

if ARGV[4] == '0' then
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as one of my comments above, worker checks existence to know if it needs to add a new delayed job while queue.add just adds repeatables whithout this check. That's my understanding from the actual logic

Copy link
Contributor

@manast manast left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, however, it would be important to improve the documentation, specially to give answers to the issues #2399 #2596

const { immediately, ...filteredRepeatOpts } = repeatOpts;

// The job could have been deleted since this check
if (repeatableExists) {
if (repeatJobKey) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment The job could have been deleted since this check is a bit confusing now since the "repeatableExists" boolean is not used anymore.

@roggervalf roggervalf merged commit 8376a9a into master Jul 16, 2024
10 of 11 checks passed
@roggervalf roggervalf deleted the feat-new-repeatables branch July 16, 2024 12:17
github-actions bot pushed a commit that referenced this pull request Jul 16, 2024
# [5.10.0](v5.9.0...v5.10.0) (2024-07-16)

### Features

* **repeatable:** new repeatables structure ([#2617](#2617)) ref [#2612](#2612) fixes [#2399](#2399) [#2596](#2596) ([8376a9a](8376a9a))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug]: Duplicate Jobs Created Despite Same Custom Key with Different Repeat Intervals
2 participants