Skip to content

Instantly share code, notes, and snippets.

@Xliff
Created October 18, 2022 02:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Xliff/b950e7e0080f3c2e9bac849497814808 to your computer and use it in GitHub Desktop.
Save Xliff/b950e7e0080f3c2e9bac849497814808 to your computer and use it in GitHub Desktop.
A Simple Cron

Here's something I wrote for guifa a couple of days ago. I am thinking of turning it into a simple Rakuish event loop for my projects.

Is this a fairly decent implementation, or is this just NIH for cron?

Please share your thoughts.

my %suppliers;
our %shifts is export;
my %times;

my $master = DateTime.now;

class TimeEvent {
  has $.time is built;
}

my $minute-time = $master;
for <minute hour day week month year> {
  %suppliers{$_} = Supplier::Preserving.new;
  %shifts{$_}    = -> { %suppliers{$_}.Supply };
  %times{$_}     =  $master;
  start loop {
    await Promise.at(
      Instant.from-posix: (
        %times{$_} = %times{$_}.later( |("{ $_ }" => 1) ).truncated-to($_)
      ).posix
    );

    %suppliers{$_}.emit: TimeEvent.new( time => %times{$_} );
  }
}

react {
  whenever %shifts<minute>() -> $e {
    CATCH { default { .message.say } }

    say "Minute shifted for event { $e.gist }";
  }
}
@vrurg
Copy link

vrurg commented Oct 24, 2022

Not comparing to cron, but two things I spotted:

  • a hash with fixed keys is a class with attributes
  • consuming a thread which would remain dormant most of the time is not necessary. .then on Promise could probably replace it

@Xliff
Copy link
Author

Xliff commented Oct 24, 2022

Responding:

  • The whole point of the example was to give it without much infrastructure. Your point though, is well made.
  • What would you repalace with Promise.then? The start loop or the react?

@vrurg
Copy link

vrurg commented Oct 24, 2022

The start loop. Though it would look a little weird. :) BTW, another solution is to have a single looping thread and use Supply.interval. The whole point is to minimize hidden usages of our otherwise limited thread pool.

@Xliff
Copy link
Author

Xliff commented Oct 26, 2022

Huh! So you think a better way is to drop the start loop and replace the hash items with Supply.intervals representing the various time periods?

@vrurg
Copy link

vrurg commented Oct 26, 2022

Let me clear this out: my primary point is to prevent extra consumption of threads. Yet, it is not even possible to get rid of at least one thread without enforcing user code to run within some kind of event loop, and let's not be that extreme! :)

Speaking of possible single-threaded implementations I have the following options in mind for the moment:

  • await Promise.any(@promises-for-each-interval) – this one I just've came up with, but it would be rather cumbersome to implement.
  • Individual Supply.internval for each option. Probably too much considering that most usages would stick to 1-2 options.
  • Single Supply.interval and events produced based on seconds passed since some reference point.
  • Just a loop with sleep 1 and then the same as above.

Not sure which approach would be the best for the task, but tend to see the last one as the most simplistic and easy to comprehend.

@Xliff
Copy link
Author

Xliff commented Oct 26, 2022

I think I would prefer the second, as it wouldn't impose too much change over the listed code, and would be more flexible. What do you see as the drawbacks of this?

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment