-
Notifications
You must be signed in to change notification settings - Fork 4
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
Job completion notification #93
Comments
As it stands, there is no "notification" functionality built in. With that said, the For situations in which you're using the PG or Redis backends in separate processes, I would point you toward calling PG's If neoq had some sort of first-party "notification" system, what would you envision that looking like? What do you consider a notification? Would notification payloads be arbitrary, similar to |
For my use cases, the eg web interface or api server accepting requests from users, then distributing tasks (via Example tasks that get distributed are:
I was kind of expecting some kind of notification to be available for jobs after they've been enqueued. Along the lines of:
Or alternatively, maybe a new method that's more synchronous?
Does that make sense? 😄 |
Yeah what you describe makes sense. It's akin to calling Sidekiq's Let me give it some thought. To set expectations, I'm not sure that this is something I want for neoq yet. It may be, but I want to give it some thought first. The most likely implementation would be something akin to your latter example, but it would return a channel and an error, e.g. done, err := nq.Execute(context.Background(), j)
select {
case job := <- done:
if job.Status == "error" {
...
}
case <- timeoutChan:
// timed out waiting for job to complete
} I just need to consider whether this is a use case that I'd like neoq to support. |
Cool, if it's a use case that you reckon Neoq should support, then I'm happy to try out potential implementations as you come up with them. 😄 |
This is unfortunate, as without this capability Neoq will be unusable for us: acaloiaro/neoq#93 Taking another look at the Neoq project and docs, this lack doesn't seem to be clearly documented either. Not sure if completion notification capability should be expected in a job scheduling library though, as the only other one I'm somewhat familiar with is RabbitMQ (which has it). Neoq's job fingerprinting capability may cause problems for us too later on, if that can't be disabled. We defininitely don't want to stop people running a particular task more than once (aka "increment value foo", "create database abc", etc).
@acaloiaro What are your thoughts on this so far? 😄 |
Hey @justinclift, I'm still mulling this one over and I think it's a decent idea. I'm more inclined to add it than not add it. With that said, "it" will probably not be exactly what you've described here. "It" will likely be a generic mechanism for receiving job updates. Something along the lines of What I'm somewhat torn about here is that I think In the mean time, if you're using the Postgres backend, you can cobble together a job status watcher yourself by polling the
I used a polling mechanism here, but a much more resource-friendly version would look like a channel that waits on That way, any time a new notification comes over the |
Thanks, I'll probably try that out some time in the coming week. Was pointed to a few other things that need investigation first (unrelated to this) though.
Instead of an API-breaking change, maybe add a new function?
|
I saw a note on your connected issue about job fingerprints. It might be relevant to you that the fingerprint is unique for both the value of the job's `Fingerprint` field, _combined_ with its `Status`. So there can only be one unprocessed job per `Fingerprint`, but there can be multiple jobs with the same `Fingerprint` that are already processed.
|
Thanks, that sounds re-assuring. 😄 |
This will likely be one of the next items I pick up to work on @justinclift. Do you have anything to add since we last discussed it? |
Nope, but am looking forward to trying this out. 😄 |
As a data point, I took some time over the last week to implement a job queue system with completion notification for my main focus project. Based the first pieces on your blog post. 😄 It's now running in production, but no idea (yet) how real world stable it is. In theory (!) it should be ok, but time will tell. 😄 |
The hardest piece (for me) was figuring out how to implement a system that returns responses to callers. At first I wasn't sure how to do it, but after trying a few things out I went with a system that uses goroutines and channels: The underlying data type used to distribute responses to the matching caller: The matching code that uses this data structure: https://github.com/sqlitebrowser/dbhub.io/blob/master/common/live.go#L686-L707 (called automatically from here) It's probably not the greatest approach, nor the greatest code, but it might be useful food for thought. 😄 |
Thanks for sharing that @justinclift. This looks pretty neat, and similar to what I have in mind. I definitely want neoq's implementation to be channel-based, and likely generic-based as well. Was there anything that stands out to you as particularly difficult to get right, implementing your solution? I haven't read through all your code yet, but I assume there's a channel-per-synchronous call. Is there anything in place to prevent the open channel list from monotonically growing? I'd like this feature to be resource-friendly so users can place some constraints on waiting for jobs to complete. Maybe deadlines for the channel(s) to produce results. I've been working on commercial software the last couple weeks (that use neoq under the hood), but I do plan on coming back to this. Unfortunately my commercial endeavors don't (yet) have any queue-and-wait needs, which is why I haven't gotten around to this. Would be happy to accept contributions if anyone is interested. |
Nah. Our infrastructure doesn't have a huge amount of load, so performance optimisations are just "nice" rather than a requirement. If the load starts growing a lot then of course that'll need to be re-visited. 😄 The main piece our code uses to direct responses to callers is a simple map:
As each job gets a (The map is mutex guarded with appropriate lock()/unlock() calls for safety, and the approach seems fine for our purposes (thus far).) When the database connection receives a NOTIFY, it grabs the details (from the database), looks up the matching job_id in the map mentioned above, then forwards the details of the response to the caller channel. (and removes the the caller entry from the map, as it won't be needed again)
That makes sense. I don't really mentally grok how to use context's properly yet (likely just needing some thought and practise to fix that), so everything that uses them (for me) is just using context.Background. So far. At some point I'll get around to understanding them better, but nothing I've worked on has really needed it yet. 😄 |
@justinclift I'm happy to share my |
Thanks. I'll do that, although not today. 😄 |
Just stumbled over a potential gotcha / food-for-thought while looking into potentially implementing two phase commit using my above approach. It looks like
Not yet sure if it'll be a real problem, but it's unexpected (by me at least). 😉 |
That's interesting. Thanks for sharing it.
I _think_ you should be fine, so long as you keep `LISTEN/NOTIFY` on separate connections (you should).
Neoq multiplexes all queue `LISTEN`s on a single connection. The connections used to complete/work jobs are separate so that `LISTEN` and `NOTIFY` events may continue independently.
See the last merged PR if you want to see an an example of how that works.
|
Am trying to figure out how enqueued jobs get notified they've been completed, so the task that enqueued the job knows to look for a response (eg in the backend database or wherever).
But I'm not seeing any info about it, and the channel pieces in the examples seem more just to keep the examples from not quitting more than anything.
Any ideas? 😄
The text was updated successfully, but these errors were encountered: