I Did Rust 1. job_scheduler

Samabo
4 min readSep 25, 2022

--

Hopefully something I commit myself to do every by-week, in this first episode we ‘ll talk about rust scheduling library. My favorite use case a tip and a caveat with it.

Quick prelude

Hi my name is Samuel. I want to commit my self to do by-weekly rust library walk through/explanation/review/showcase. Where i will try to show you a cool library/project to use at work or for the next pet project to collect the dust. There are multiple reasons for me to do this which includes:

  • Verifying my rust skill
  • Trying out new rust libraries/projects
  • Improve in my writing

The last one is probably the one that needs most improving. Because I’m from Slovakia, small Slavic country in Central Europe. I am a self taught developer interested in: Wasm, Embedded systems, Music.

Ok that’s it for prelude. Let’s checkout job-scheduler

From the glance at the crates.io page you might presume that it’s a dead library and doesn’t have a use case in today’s code-bases.

However don’t get fooled by the last update date. This is one of my favorite libraries to use

Ok, sooooo what is it?

Well as the name suggests, it schedule’s jobs. It utilizes a cron like interval specifier that is easy to use due to its vast usage in Linux distributions. To run your function (“Job”) at a precise interval/time. Precision being the keyword here, and the one of the things i love about this library. I’m not going to copy paste here the library documentation,firstly because i suggest you to check it out your self and secondly to showcase my favorite features. Precision, yes! As i mentioned i love this library’s scheduler implementation due to the fact that it exposes tick() function which on every its call checks if its time to run your job. If it is the time to run the function well, it runs your function, simple yeh?

So you are in charge on how precise do you want your scheduler be. If you want extremely precise scheduler just call tick() all the time like this:

let scheduler = JobScheduler::new();loop {
scheduler.tick();
}

However as mentioned in the library docs this is inefficient because you don’t really need to specify precision under 300 milliseconds mostly due to the fact that the cron schedule doesn’t support millisecond intervals.

Non blocking jobs:

This example idea is about running long task or more correctly blocking task without blocking other jobs on the same thread. You might know blocking and non-blocking terms from async rust. But we are not going to talk about async in this post at any point. All of this code is mostly intended to be used in concurrent application. However i think its possible to do some modifications to the library making it usable in async context. Also as of writing this i spotted this gem that i might do an episode as it looks very much intended for asynchronous context if you are looking mostly for async implementation of this idea.

Caveats:

The first problem that will come up when you try to implement this will probably be that you have to always clone/copy variables so that the borrow checker is happy. Let me show you some bad code:

This will produce quite verbose error:

error[E0507]: cannot move out of `user.name`, a captured variable in an `FnMut` closure
--> src/lib.rs:21:27
|
15 | let mut user = User {
| -------- captured outer variable
...
20 | let job = Job::new(schedule, move || {
| ______________________________________-
21 | | thread::spawn(move || {
| | ^^^^^^^ move out of `user.name` occurs here
22 | | user.name = String::from("Daniel");
| | ---------
| | |
| | variable moved due to use in closure
| | move occurs because `user.name` has type `String`, which does not implement the `Copy` trait
23 | | }) ;
24 | | });
| |_________- captured by this `FnMut` closure

To be totally honest i don’t really understand full extend of this error message, but i will try to do my best with hope that someone will correct my explaining if necessary. So in essence you are trying to move a part of struct from closure(“job closure”) to the thread closure. But our ‘user’ value is captured by closure(“job closure”) by the ‘move’ keyword and the borrow checker doesn’t allow capturing a value from a closure that is captured from other scope.

To fix this we have to give the thread closure some concrete variable that can be captured. Also it can’t be a reference, due to the ‘job closure’ move, it does what is says, it moves the value and even a mutable reference becomes a problem because you would have to specify its lifetime and that is as far as my understanding goes, impossible. But you can clone or copy, and do something like this:

Alright that’s all i have, hopefully you got something out of this. It would be delightful if you could follow me, as i want to reach 100 followers and make it into partner program. Thank you, goodbye

--

--

Samabo

23y/o slav from slovakia, that likes to code and sometimes share my journey on the internet.