Ceylon 1.3.3 Future timeout cancellation: JVM vs JavaScript backend differences
0 reputation · 04 Jul 2021, 07:22 UTC
0 reputation · 04 Jul 2021, 07:22 UTC
When applying a timeout to a ceylon.concurrent.Future using orElseAfter in Ceylon 1.3.3, the implementation cancels the underlying task with cancel(true). The language tour notes that the actual stopping of the computation depends on the executor and may differ between the JVM and JavaScript backends, leaving the cancellation behavior unspecified.
Developers need to know whether a timeout guarantees that the timed‑out computation has ceased, especially when resources such as sockets or locks must be released reliably.
What guarantees does the orElseAfter timeout provide about task termination on each backend? Does future.isCancelled() become true immediately after a timeout expires, or can the state lag? Is there a documented way to obtain deterministic cancellation, or must users rely on backend‑specific executors to achieve it?
34775 reputation · 04 Jul 2021, 17:31 UTC
No. In Ceylon 1.3.3, orElseAfter gives you a deadline for the result, not a guarantee that the timed-out computation has stopped. The returned future completes with the fallback once the delay elapses. Any cancellation of the original future is a request forwarded to the executor; it is not evidence that the task has terminated. That holds on both the JVM and JavaScript backends.
Treat orElseAfter as a race between two futures: the original and a delayed fallback. When the delay wins, the implementation asks the original future to cancel — on the JVM this is typically an interrupt-style request, on JavaScript a flag or promise rejection. In both cases the request is cooperative, and the executor decides what, if anything, happens next.
cancel(true) can unblock operations defined to respond to interruption, such as Thread.sleep, Object.wait, and interruptible channel operations.isCancelled() reports that a cancellation request was recorded, not that the task stopped. It can lag behind the deadline because the timeout callback is itself scheduled work. On the JVM the lag is usually short; on JavaScript, synchronous work can push it out arbitrarily. Do not use it as a completion signal.
There is no portable, documented guarantee of deterministic termination across backends. Determinism has to come from your own code:
finally blocks rather than after the timeout.Illustrative pseudocode — adjust to the actual 1.3.3 signatures in your SDK:
value work = startAsync(() {
while (!token.cancelled) { // cooperative checkpoint
processOneChunk();
}
});
value result = work.orElseAfter(deadline, fallback);
The fallback completing tells you the deadline passed. It does not tell you the loop above exited.
ceylon.concurrent sources shipped with your Ceylon 1.3.3 distribution and read the orElseAfter and cancel paths for both backends.isCancelled() flips and when the task body actually exits.finally block after a timeout to see whether cleanup runs promptly or waits for the task to finish.Because executor behavior dominates here, confirm findings against the specific executor you use rather than assuming the results generalize.
Which executor runs the timed-out tasks? If it is a thread pool whose tasks are interruptible, cooperative checks plus finally cleanup are usually enough. If it is a single-threaded or event-loop executor — typical on JavaScript — no timeout can preempt the work, and you must design the task to yield and check cancellation itself.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.