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

Feature request: Support async unref for timers #6141

Closed
cknight opened this issue Jun 6, 2020 · 7 comments · Fixed by #12953
Closed

Feature request: Support async unref for timers #6141

cknight opened this issue Jun 6, 2020 · 7 comments · Fixed by #12953
Labels
cli related to cli/ dir feat new feature (which has been agreed to/accepted)

Comments

@cknight
Copy link
Contributor

cknight commented Jun 6, 2020

Use case: As a a module developer, I want to run periodic tasks during the execution of my module. This can be accomplished via setTimeout or setInterval for example. However, I do not want these timers to block the exiting of my module. setInterval in particular will cause the module to run forever until the id associated with it is cleared.

Specific use case: std/log file handler now uses a buffer to write log messages. Google and Go's glog implementations both use a log daemon to flush the buffer automatically every 30 seconds. It would be good for std/log file handler to use setInterval to flush the buffer every 30 seconds as well to mimic this but not block module exit. (see also ref #6127)

For starters, there is already support for async unref ops within Deno which would likely be used in this solution.

@ry ry added cli related to cli/ dir feat new feature (which has been agreed to/accepted) labels Jun 6, 2020
@tumile
Copy link
Contributor

tumile commented Jun 17, 2020

Hi @cknight, @ry, I would like to pick this up. My plan is as follow

  • Add unref property on Timer
interface Timer {
  ...
  unref: boolean;
}
  • Add unrefTimer(id: number) function that unschedules the timer, set unref then reschedules it
  • Pass unref to op_global_timer and return an according JsonOp
if args.unref {
  Ok(JsonOp::AsyncUnref(f.boxed_local()))
} else {
  Ok(JsonOp::Async(f.boxed_local()))
}
  • When processing nextDueNode, if a single timer has unref=false then pass unref=false to op_global_timer

@kitsonk
Copy link
Contributor

kitsonk commented Jun 17, 2020

Why is clearInterval and clearTimeout not sufficient?

@cknight
Copy link
Contributor Author

cknight commented Jun 17, 2020

Why is clearInterval and clearTimeout not sufficient?

@kitsonk In short, because a sub-module may setup the timeout or interval, and a sub-module can never know when the process is complete. Therefore, the sub-module cannot call clearInterval or setTimeout. This responsibility would need to be passed to the main module, which makes for awkward design and poor UX.

Specifically, for my use case mentioned above, I had wanted to run a flush() of a log buffer every 30 seconds in the std/log library. The logging module cannot know when the module using it is 'done'. unload is never called as the interval is still forever firing. Therefore a way to schedule tasks which don't block the process from completing is desirable.

@kitsonk
Copy link
Contributor

kitsonk commented Jun 17, 2020

Understood... would window.onclose/window.addEventListener("close", () => {}) be sufficient?

We should try to extend browser paradigms where possible.

@cknight
Copy link
Contributor Author

cknight commented Jun 18, 2020

If I understand you correctly, window.onclose/window.addEventListener would still require the user to take action to terminate the process, either through extra code in the main module where the developer determines the module is complete or manual intervention during the run. Neither feels good UX to me and, in the general for the use cases discussed above, the interval or timer started within the sub-module is an implementation detail which the developer and main module don't need to know about.

Browser windows "run" forever until closed by the user. This is a different paradigm to a deno process which can have a natural end.

@kitsonk
Copy link
Contributor

kitsonk commented Jun 18, 2020

Looking at how Node.js does it, I can see your point...

It feels like Deno.unref(id: number): void; and Deno.ref(id: number): void; would be appropriate, with the same semantics as clearTimeout() which is invalid IDs are just a noop.

@ejsmith
Copy link

ejsmith commented Jul 20, 2021

I just ran into this issue as well. I want to use setInterval to have code executed periodically in my program, but I do not want it to block the exit of the application when the main code has completed. Has there been any progress on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cli related to cli/ dir feat new feature (which has been agreed to/accepted)
Projects
None yet
5 participants