It is my understanding that, being a Task, it can fail, but in which ways can it fail?
Also, I noticed there’s not an explicit way to cancel a timeout, so I went for the elm source code and found this: there’s a clearTimeout in there, so I wonder what’s going on: is there a way to use it?
Again, not that I need this, but what’s the story around this?
Thank you!
Tasks in general can fail, but this Task in particular cannot. You can tell by looking at the type signature: sleep : Float → Task x (). The error type is x and that type variable isn’t present anywhere else in the signature. That means there’s no way for sleep to create an error of type x.
If it isn’t clear why that’s the case, try this example:
myError : Result x ()
myError =
Err ? -- What should I replace the ? with
the answer is you can’t. The only thing that would work here is Ok ()*
As for clearTimeout. I’m not sure exactly what that is there for. Maybe it’s used internally or maybe it’s the start of some API for cancelling Process.sleep that hasn’t been finished yet (similar to Process.spawn and Process.kill)
If you did need a way to cancel a Process.sleep, I’d do it by updating a field in your Model that the Task checks when it triggers an update to not do anything.
*Sure, you could use Debug.todo "" or use a function that never halts but that just delays the issue until runtime.
A secondary feature of a Task is that you can stack them using Task.andThen. This allows you to execute another Task after waiting for a certain number of seconds.
Practical example
As the developer of the Matrix SDK, this is incredibly useful for ratelimits. I have a certain Task type that does an HTTP request to the server, but sometimes the server returns the following JSON:
{
"errcode": "M_LIMIT_EXCEEDED",
"error": "Too many requests",
"retry_after_ms": 2000
}
Using Process.sleep, I can redefine my Task with the following function:
{-| Catch ratelimits
-}
allowRatelimits : Task a b -> Task a b
allowRatelimits task =
task
|> Task.mapErr
(\data ->
if data.errcode == "M_LIMIT_EXCEEDED" then
Process.sleep data.retryAfterMs
|> Task.andThen (allowRatelimits task)
else
Task.fail data
)
This is a complex function, but it basically does the following:
It makes the HTTP call.
If it gets the ratelimit error, it waits for that time using Process.sleep.
It tries again.
TLDR
Process.sleep lets you execute another Task after a minimum number of milliseconds. It helps you execute tasks in the future.
Thank you all for the great answers! Now it’s clearer, but I still have to take a look at Process.kill and understand how it combines with Process.spawn.