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

Find if there is a pending instance of a given job #58

Open
yched opened this issue Jul 15, 2018 · 4 comments
Open

Find if there is a pending instance of a given job #58

yched opened this issue Jul 15, 2018 · 4 comments

Comments

@yched
Copy link

yched commented Jul 15, 2018

For a couple use cases (detailed below), I would need to find if there exists pending instances of a given job.

Unless I'm missing something, it seems the current API offers no way of doing that ? (aside from using internal methods or querying the jobs collection directly, which might break on subsequent package versions)

My use cases :

  • Setting up "cron tasks" on startup :
    With the new features in 3.0 I can have jobs that reschedule (well, replicate()) themselves at a later date after completion.
    On app startup I register the callbacks, and then need to schedule the 1st run - but only if there is no pending run already scheduled from a previous startup
    (Think of a deploy that adds a new cron task that didn't exist before)

  • Debouncing execution of a task between web backends :
    We host our app on several (well, 2 at the moment) servers behind HAProxy.
    There are some expensive tasks, triggered by user frontend action received by DDP method, or by external services through an HTTP route, that we would like to debounce. That debounce needs to cover calls triggered by any of the servers.
    I was thinking of doing that by scheduling a job for execution a couple seconds later - but only if an instance isn't already pending.

@wildhart
Copy link

wildhart commented Jul 31, 2018

I agree with this. Here's a few helper functions I've written for myself:

Jobs.findAndDelete = function(jobName, param) {
    const query = {};
    if (jobName) query.name = jobName;
    if (param) query.arguments = param;
    const count = Jobs.collection.remove(query);
    //console.log("Jobs.findAndDelete", jobName, param, count);
    return count;
}

Jobs.count = function(jobName, param) {
    const query = {};
    if (jobName) query.name = jobName;
    if (param) query.arguments = param;
    const count = Jobs.collection.find(query).count();
    //console.log("Jobs.countWithName", jobName, param, count);
    return count;
}

Jobs.runOnce = function(jobName) {
    if (!Jobs.count(jobName)) Jobs.run(jobName);
}

It would be great if similar or better functions could be built-in.

My use cases include:

  1. I want the server to run a repeating job every 4 hours (initiating subscription payments/reminder emails, etc). But I only want one server to run this job and only if the job isn't already scheduled. For this I use my helper Jobs.runOnce("checkAccountExpiration")
  2. When my server sends an email to user I create a job to send me a warning if it wasn't delivered within 20 seconds. When I get the webhook that the email was delivered I delete this job. For this I do Jobs.run("forwardDelayedEmail", address, options, {in: {seconds: 20}}) when sending an email and then Jobs.findAndDelete("forwardDelayedEmail", address) when I get the delivered webhook

Note that Jobs.count and Jobs.findAndDelete can only search for one parameter - this is fine for my needs so far but better functions should be able to match multiple parameters with AND. Plus Jobs.runOnce doesn't take any extra parameters or options.

@charlesdeb
Copy link

Yes, I think something like this would be helpful - although since I am brand new to this package, I may be missing something obvious.

I want the ability for a specific jobs to be scheduled/removed from a given queue, but I don't see how to get the jobId without querying the Jobs collection with parameters as @wildhart is doing. Or should register these jobs with some unique ID in the Job name and stop/start their queues using their names? In my use case, that would create a lot of different queues (all with slightly different names) all doing pretty much the same thing - so I don't think that is the right approach.

@msavin
Copy link
Owner

msavin commented Jan 13, 2019

I've recently ran into this issue while making https://www.hndetox.com, and here's what I figured.

  1. I'm open to being challenged on this; I think that Jobs.collection() should be used for finding jobs, simply because MongoDB's API is great. Any API I would make here would either be more limited, or end up looking like MongoDB's API. For the same reason, I have been considering removing Jobs.clear(), as once again, I think it would be easier for most people to use the MongoDB API rather than learn a new one.

  2. There has been support for a singular flag, though undocumented. I recently updated the package to also support unique flag, and both are now documented in Documentation.md.

A copy-paste from the documentation with more info on these fields:

  • unique - Boolean
    • If a job is marked as unique, it will only be scheduled if no other job exists with the same arguments
  • singular - Boolean
    • If a job is marked as singular, it will only be scheduled if no other job is pending (or failed, which in effect, is the same as pending) with the same arguments

These two will run a query before inserting the job. You can see their code in imports/server/actions/add

@charlesdeb
Copy link

@msavin you updated the docs for these two "new" methods a couple of days after I implemented something similar myself based on what @wildhart had suggested. Although I have not refactor my code to use your methods I think they are exactly what I was wanting at the time. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants