supercronic icon indicating copy to clipboard operation
supercronic copied to clipboard

Support @reboot command

Open hongkongkiwi opened this issue 8 years ago • 23 comments

Hi there,

I'm currently running supercronic in a docker and it's working great.

I would like to run my script on "boot" e.g. when supercronic is started, as well as at a set interval. Normally in many cron versions we can use the standard @reboot to run a script on reboot, but in my testing it looks like supercronic doesn't currently support this.

Would it be possible to add this functionality? I notice that other shortcuts such as @hourly are supported.

I do have a work-around which is to run a shell script /start-container which simply runs my script and then runs supercronic, but it seems a bit awkward!

hongkongkiwi avatar Apr 10 '18 07:04 hongkongkiwi

What's your expectation for what @reboot would do? Run the job upon Supercronic starting up?

(I'm a little concerned about this being potentially confusing, since that's not what you'd normally expect from a @reboot in regular cron)

krallin avatar Apr 18 '18 09:04 krallin

Yes that is right, I would expect supercronic to run the script when it first starts up.

That means I can have both an hourly and a startup command all in the same cron file (which makes it pretty clear).

Here is my use case.

  1. When the Docker starts up it runs a run system called runit.
  2. Runit must start as PID 1, so therefore entrypoint looks like this ENTRYPOINT ["/sbin/runit-init"]
  3. Supercronic is a runit service so it will get started immediately, my script runs every 30 minutes
  4. My script that is running is a bash script (and not a service) so it cannot be started using runit

So you can see my problem, there's no way in this configuration to run some arbitrary script after runit. How I would handle this on other systems might be to do something like @reboot in the crontab so that after the cron daemon starts up it will run this script once.

The only other workaround for now is to have a service that runs once off scripts, but that's quite awkward.

hongkongkiwi avatar May 11 '18 08:05 hongkongkiwi

I'm looking for this feature as well.

Maybe rather than @reboot, we call it @cronstart so as not to confuse with the act of a system reboot.

With @reboot, I fear one might infer the prefixed cron job will only run on system reboots.

@krallin - Would you be open to a PR adding this feature?

cgons avatar May 27 '18 18:05 cgons

@cgons yes, with the minor caveat that I think @start would be a simpler / appropriate name for the event. We'll want to make sure to document that this is non-standard though.

krallin avatar May 28 '18 07:05 krallin

Sounds like a great solution! Looking forward to the PR.

hongkongkiwi avatar May 29 '18 06:05 hongkongkiwi

Awesome, @start it is! I'll try and get started ASAP.

BTW, is this the correct place to talk about implementation details (ie what I plan to change/add etc...)?

cgons avatar May 29 '18 23:05 cgons

@cgons sure, that's fine :+1:

krallin avatar May 30 '18 15:05 krallin

Any progress on this @cgons ? I work around this by adding a docker-entrypoint.sh file, but I would love to get rid of this extra process handling and have everything done within supercronic.

hongkongkiwi avatar Nov 26 '18 05:11 hongkongkiwi

Sorry, I had to go an pat. leave for a few months and ended up having negative free time to work on this. I'm back now and I want to try and get this working over the next few days/weeks.

I'll post here with an update. Be on my case though as that's a motivator to get this implemented! :)

cgons avatar Dec 13 '18 18:12 cgons

@krallin - I was thinking of creating a PredefinedExpression class that implements the Expression interface and returns zero value time after it has been run once (via the implemented Next() method).

Inside parseJobLine() I would check if the line starts with @ and if so, attempt to parse it as a PredefinedExpression. If the @ does not match the list of predefined expressions (which for now would be just @start), then it would return a error and we can then attempt to parse it using cronexpr.

I have to think a little more about how to keep track of when the job was run and where to store that state. I should probably take advantage of the cronIteration counter...

Let me know what you think.

cgons avatar Dec 15 '18 22:12 cgons

I think you should instead create a separate interface that wraps the existing cron expression interface, because you're also going to need a IsDone method or some such to represent that the StartJob goroutine should exit after running this job once.

I'm not clear on why you suggest Next() should return 0. I'm not certain I understand what this achieves here?

krallin avatar Dec 17 '18 10:12 krallin

Yep, that's what I'll have to do. I was trying to get away with making a minimal amount of changes but, as you pointed out, that won't really work.

I'll get this working in a branch on my fork and then ping you. I can then make any changes you'd like to see.

cgons avatar Dec 19 '18 14:12 cgons

yes, with the minor caveat that I think @start would be a simpler / appropriate name for the event. We'll want to make sure to document that this is non-standard though.

I'm not really fan of having a new (non-standard, supercronic-specific) directive, like @start. @reboot is already documented as "schedule this job only once, when crond starts up" in dcron.

The Vixie cron manual (which, AFAIK introduced this directive) just says "run once after reboot"; but the debian version of the manual page states: "Please note that startup, as far as @reboot is concerned, is the time when the cron(8) daemon startup. In particular, it may be before some system daemons, or other facilities, were startup. This is due to the boot order sequence of the machine.".

romain-dartigues avatar Jan 24 '19 10:01 romain-dartigues

Sorry, couldn't wait until someone started the implementation. I implemented the issue. Unfortunately this was my first contact with Golang. So please don't expect too much :-). Besides, it is somehow a hack ... But for my purposes it works.

I have extended the translation table in Cronexpr: "@start", "*/1 * * * * * * *". So this job starts every second. In the supercronic I check if the job was generated from an @start and terminate it after a single run. To leave some time for @start processing, I introduced a parameter "-delay". The line with @start must be at the first position. And @start may occur only once.

https://github.com/dmaj/supercronic https://github.com/dmaj/cronexpr

Sample: @start touch /home/golang/etc/test.txt */1 * * * * * * echo "hello"

dmaj avatar Jun 16 '19 10:06 dmaj

Maybe this is interesting for others as well. I solved the @reboot topic for me by simply doing a one off execution of my cron tasks before actually starting supercronic. This is easily doable since I am not mounting my crontab file into the container, but actually generate it at container startup. This has for me the added benefit that I am making sure that the cron jobs work at all (else the container would fail to start).

Code is at https://github.com/zokradonh/kopano-docker/blob/e0792a39a5d5ea83203647f303350101df97e590/scheduler/start.sh#L35

fbartels avatar Jun 19 '19 15:06 fbartels

i created a pull request to implement this issue. in the first run of the main loop i execute all jobs with the expression @start. after then the other periodic jobs will be scheduled. the pr is reload safe.

phin1x avatar Jun 19 '19 16:06 phin1x

Awesome! Can we get this merged?

hongkongkiwi avatar Feb 05 '20 06:02 hongkongkiwi

would love to see this merged

MikeC-BC avatar Jun 24 '20 04:06 MikeC-BC

Actually I would prefer @reboot instead of @start as it is supported by all cron replacements. You can just make it clear in documentation that @reboot means "run once after cron is started".

I would avoid using nonstandard name as @start because probably it would break some existing parsers.

dex4er avatar Jul 03 '20 15:07 dex4er

was this ever implemented? Would be a really nice feature

dmitrypol avatar Sep 19 '22 16:09 dmitrypol

I would also like to know if there is a way to run a script only once. I do not exactly need a @reboot command or anything. The reason is: I use a container I created based on alpine and supercronic and on most occasions I use it to comfortably run scripts in a loop, but I've had occasions I only wanted to run the script once.

Currently I need to override the initial command in my deployment.yaml, but it'd be much nicer if I just could specify an environment variable or anything really to only execute a script once (a CLI command, that I could insert into my query.sh script would also be fine). I do not feel like using pkill or something like that.

divStar avatar May 17 '23 22:05 divStar

I'm still crossing my fingers on this. It's been a year since the last update, any movement on this (whether it's @start or @reboot or @cronstart I don't really care :D)

mmguero avatar Aug 13 '24 14:08 mmguero

Having @reboot work as expected would save us an initContainer, as the main container can just use a health probe to wait for Supercronic to do its thing on start-up and we don't have to introduce a special-case for the initial situation.

I also think there's some newer sidecar container functionality on the horizon in Kubernetes that introduces containers that wrap the main container lifecycle and exist before, during and after. This makes it possible to run Supercronic even before the main container to start executing tasks, and hence the @reboot functionality becomes pretty interesting.

wvh avatar Jan 14 '25 06:01 wvh