-
Notifications
You must be signed in to change notification settings - Fork 75
added cron tutorial #1515
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
added cron tutorial #1515
Conversation
Signed-off-by: macolso <[email protected]>
|
FWIW I would not block this on updating the command reference but we would want to update the plugin install instructions so people get the 0.3 version. |
| - [Next Steps](#next-steps) | ||
|
|
||
| This tutorial guides you through the process of scheduling HTTP requests in a Spin application running on Fermyon Wasm Functions using cron jobs. The `spin aka cron` command allows applications to receive scheduled HTTP triggers without relying on external services. In this tutorial, you'll learn how to define and manage cron jobs using the `spin aka cron` command. | ||
| This tutorial guides you through the process of scheduling HTTP requests in a Spin application running on Fermyon Wasm Functions using cron jobs. The `spin aka crons` command allows applications to receive scheduled HTTP triggers without relying on external services. In this tutorial, you'll learn how to define and manage cron jobs using the `spin aka crons` command. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spin aka cron is allowed and may be less jarring.
(I rather feel the long form should be spin aka cronjobs. I've never heard crons as a plural before. But maybe I just mix in the wrong circles!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can also consider changing the plugin if we all agree that the nomenclature is off. We did not think long and hard about the most appropriate name. Considering the functionality is labeled as experimental, breaking changes are probably fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also lean towards cron -- feels a bit more natural.
Also a good reminder I should flag that this feature is experimental in the tutorial
| # Create Spin application | ||
|
|
||
| Spin is a lightweight framework for building WebAssembly microservices and applications. It allows developers to define cron jobs that execute functions at scheduled intervals. To simplify development, Spin provides templates for various use cases, including scheduled tasks. | ||
| You must have a running Spin application on Fermyon Wasm Functions to apply the cron trigger to. We'll create a new Spin application for scheduling tasks using cron jobs using the `http-js` template: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The application isn't "for" scheduling tasks is it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right - it's not intended for scheduling tasks but the wording is a bit misleading. I've reworded this sentence.
| ``` | ||
|
|
||
| ## Creating a Cron Job for your Spin application | ||
| We'll go ahead add a specific path for our cron trigger in later steps: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a HTTP trigger which we will run from a cron job. Sorry for the pedantry but "cron trigger" is a specific thing and if we say this is a cron trigger we will cause a measurable muddle!
|
|
||
| Now we will use the `spin aka crons` command to invoke the Spin app's HTTP endpoint at our desired interval. The syntax for this request follows standard crontab format. | ||
|
|
||
| > `spin aka cron` supports single digits in each cron expression field and intervals in every position except the day of the week (e.g., `* */12 * * *` for every 12 hours). The smallest supported cron configuration is every 5 minutes (`*/5 * * * *`). Other syntax elements like comma-separated lists and ranges are not supported. Please feel free to[leave feedback](https://fibsu0jcu2g.typeform.com/to/G2u4tPcP) if your desired range is not supported. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is "single digits" correct? You can't use double-digit numbers for e.g. day of month or hour of day?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can, and the point about comma separated lists and ranges (which is from the original cron proposal) is actually not currently correct (they are supported). See my previous point about how we're currently allowing anything that happens to work with the libraries we're using, and we need to be a bit more strict about it.
|
|
||
| # Creating a Cron Job for Your Spin Application | ||
|
|
||
| Now we will use the `spin aka crons` command to invoke the Spin app's HTTP endpoint at our desired interval. The syntax for this request follows standard crontab format. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Link to the dialect of the crontab format that we support
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately I've not been able to find a good, concise explainer of the syntax we support. We might want to simply write it out here. The unfortunate truth is that currently the exact syntax we support is a bit of an implementation detail. We should limit the syntax for now so that we don't accidentally support something we hadn't originally planned on.
|
|
||
| > `spin aka cron` supports single digits in each cron expression field and intervals in every position except the day of the week (e.g., `* */12 * * *` for every 12 hours). The smallest supported cron configuration is every 5 minutes (`*/5 * * * *`). Other syntax elements like comma-separated lists and ranges are not supported. Please feel free to[leave feedback](https://fibsu0jcu2g.typeform.com/to/G2u4tPcP) if your desired range is not supported. | ||
| Let's create a cron job that runs every hour. Since scheduling is based on UTC, you may need to [convert your local time to UTC](https://www.worldtimebuddy.com/?pl=1&lid=100&h=100&hf=1) to ensure correct execution. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure why local/UTC would matter for an "every hour" schedule? I'm guessing it's that the schedule is "every hour on the hour" and you're thinking about half-hour timezone offsets? Like okay I convert my local time to UTC, it's 5:08am or whatever, now what do I do with that result?
It may be better to pull out the "times are in UTC" comment to go with the scheduling/crontab discussion perhaps?
| <!-- @selectiveCpy --> | ||
|
|
||
| ```console | ||
| spin aka crons create "0 * * * *" "/hello" "hello-cron-job" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe explain what these fields are, since they are not named in the command. I'm guessing the second is the route to be hit. Is the third the name of the app to be hit? Or the name of the job? (In which case how does it know which app to hit? Is this an "app in current directory" thing?)
If the third parameter is not the name of the app, it would be good to choose a different string from the name of the app, so as to avoid ambiguity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The syntax is spin aka crons create $SCHEDULE $PATH_AND_QUERY $NAME_OF_CRON
Indeed the app that will be hit is the "current app".
| - [Next Steps](#next-steps) | ||
|
|
||
| This tutorial guides you through the process of scheduling HTTP requests in a Spin application running on Fermyon Wasm Functions using cron jobs. The `spin aka cron` command allows applications to receive scheduled HTTP triggers without relying on external services. In this tutorial, you'll learn how to define and manage cron jobs using the `spin aka cron` command. | ||
| This tutorial guides you through the process of scheduling HTTP requests in a Spin application running on Fermyon Wasm Functions using cron jobs. The `spin aka crons` command allows applications to receive scheduled HTTP triggers without relying on external services. In this tutorial, you'll learn how to define and manage cron jobs using the `spin aka crons` command. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can also consider changing the plugin if we all agree that the nomenclature is off. We did not think long and hard about the most appropriate name. Considering the functionality is labeled as experimental, breaking changes are probably fine.
|
|
||
| ## Deploy Spin Application to Fermyon Wasm Functions | ||
|
|
||
| Before applying our cron trigger, we must have our Spin application running on the Fermyon Wasm Functions platform. Deploy the application with: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to rewording away from "trigger". I would also use the terminology of "scheduling" versus "applying".
|
|
||
| # Creating a Cron Job for Your Spin Application | ||
|
|
||
| Now we will use the `spin aka crons` command to invoke the Spin app's HTTP endpoint at our desired interval. The syntax for this request follows standard crontab format. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately I've not been able to find a good, concise explainer of the syntax we support. We might want to simply write it out here. The unfortunate truth is that currently the exact syntax we support is a bit of an implementation detail. We should limit the syntax for now so that we don't accidentally support something we hadn't originally planned on.
|
|
||
| Now we will use the `spin aka crons` command to invoke the Spin app's HTTP endpoint at our desired interval. The syntax for this request follows standard crontab format. | ||
|
|
||
| > `spin aka cron` supports single digits in each cron expression field and intervals in every position except the day of the week (e.g., `* */12 * * *` for every 12 hours). The smallest supported cron configuration is every 5 minutes (`*/5 * * * *`). Other syntax elements like comma-separated lists and ranges are not supported. Please feel free to[leave feedback](https://fibsu0jcu2g.typeform.com/to/G2u4tPcP) if your desired range is not supported. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can, and the point about comma separated lists and ranges (which is from the original cron proposal) is actually not currently correct (they are supported). See my previous point about how we're currently allowing anything that happens to work with the libraries we're using, and we need to be a bit more strict about it.
| <!-- @selectiveCpy --> | ||
|
|
||
| ```console | ||
| spin aka crons create "0 * * * *" "/hello" "hello-cron-job" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The syntax is spin aka crons create $SCHEDULE $PATH_AND_QUERY $NAME_OF_CRON
Indeed the app that will be hit is the "current app".
sidebar changes, header tweaks, few verbiage updates Co-authored-by: Ryan Levick <[email protected]> Co-authored-by: itowlson <[email protected]> Signed-off-by: MacKenzie Olson <[email protected]>
|
@macolso it occurred to me that one question with this is "how do I know it worked?" What does the reader see if they follow the tutorial? Can they see the HTTP responses in cron logs, for example? (If not, what is the simplest example app that they can cron and still see an observable result? A silly example might be: an app with two routes: |
Signed-off-by: macolso <[email protected]>
|
@itowlson I had a similar niggle with this tutorial. You can actually see the HTTP responses in the cron logs! I've updated the sample application to log cron events, inferring whether it's a cron event or a direct ping based on the presence of a query parameter. Let me know if this feels like a hacky solution, and I can remove that nuance. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the update @macolso - this is much clearer now - unfortunately I still have a few niggles and typos, and at least one thing which I'm pretty sure is an error. Sorry for being picky!
| // Capture current timestamp for logging and response | ||
| const now = new Date().toISOString(); | ||
|
|
||
| // Log the trigger event, including the value of 'msg' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This only appears to log in the cron case - should the comment be moved inside the if?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to simplify the example and remove the functionality that changes the output depending on whether the app received a direct ping or a cron trigger. I agree that the added complexity outweighs the value it's providing.
| const now = new Date().toISOString(); | ||
|
|
||
| // Log the trigger event, including the value of 'msg' | ||
| if (msg) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having two code paths complicates the application. The application isn't the core point of the tutorial, it's just something we need to have, so I'd keep it as simple as possible. It already has routing for the cron-me URL which is more than enough complexity I reckon...
|
|
||
| ```console | ||
| spin aka logs -a hello-cron-job | ||
| 2025-04-02 04:00:00 [hello-cron-job] Hello, cron job triggered with msg: "fwf" at 2025-04-12T04:00:00Z |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider linking this back to the console.log statement from from the HTTP application, and maybe put some more motivation around this, both here and when you write the application. E.g. motivating the application a la "For a real cron job, you'd see its effects in the data it updates or the artifacts it produces. For this tutorial, though, we'll just emit a log, so that we can see the application has been called." and then down here we can say "This is the message we had the application log so that we could see it was being called" or something like that.
(If you keep the "different behaviour when they try it interactively" thing then it would be good to be extra clear about this because the message will be unfamiliar.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great suggestion! I added a disclaimer above the source code snippet that this is a simplified example and allude to what operations you may see in a real world example.
|
|
||
| * **Schedule:** How often the job runs, using standard cron syntax | ||
| * **Path and query:** The HTTP path (and optional query parameters) to invoke | ||
| * **Name:** The Spin applciaton to apply the cron job to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * **Name:** The Spin applciaton to apply the cron job to | |
| * **Name:** The Spin application to apply the cron job to |
|
|
||
| * **Schedule:** How often the job runs, using standard cron syntax | ||
| * **Path and query:** The HTTP path (and optional query parameters) to invoke | ||
| * **Name:** The Spin applciaton to apply the cron job to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The plugin docs say that the third parameter is the name of the cron job not the name of the application.
(If that's true, we need to explain which application it's going to hit - I assume the one in the current directory.)
(ETA: see Ryan's earlier comment #1515 (comment))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. I've updated accordingly.
|
|
||
| Now we will use the `spin aka crons` command to invoke the Spin app's HTTP endpoint on our desired schedule. The syntax for this request follows standard crontab format. | ||
|
|
||
| > `spin aka crons` supports multiple digits in each cron expression field and intervals in every position (e.g., `* */12 * * *` for every 12 hours). Syntax elements like comma-separated lists and ranges are currently supported. Scheduling follows UTC and you may need to [convert your local time to UTC](https://www.worldtimebuddy.com/?pl=1&lid=100&h=100&hf=1) to ensure correct execution during daylight savings time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't I need to convert my local time to UTC anyway, if I want it to fire at a particular local time? And then amend it at each DST change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's a good point. I liked your language suggestion below -- I will make that modification.
| - [Next Steps](#next-steps) | ||
|
|
||
| This tutorial guides you through the process of scheduling HTTP requests in a Spin application running on Fermyon Wasm Functions using cron jobs. The `spin aka cron` command allows applications to receive scheduled HTTP triggers without relying on external services. In this tutorial, you'll learn how to define and manage cron jobs using the `spin aka cron` command. | ||
| This tutorial guides you through the process of scheduling HTTP requests in a Spin application running on Fermyon Wasm Functions using cron jobs. The `spin aka crons` command allows applications to receive scheduled HTTP triggers without relying on external services. In this tutorial, you'll learn how to define and manage cron jobs using the `spin aka crons` command. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This page seems to be largely the same content as the previous one but with the "cron trigger" language back in... is this meant to have been deleted in favour of the page above? The TOC entry still points to this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, using-cron-triggers.md should be deleted and the sidebar should be updated to point at using-cron-jobs.md
| spin aka deploy | ||
| ``` | ||
|
|
||
| Upon successful deployment, you should receive a domain name that you can use to test the application: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider shoiwing the deploy output so they can see where to find the domain name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added, good suggestion!
Signed-off-by: macolso <[email protected]>
|
@itowlson Excellent feedback—thank you! I've taken another stab at addressing the concerns. I think it flows much better now, and I agree that the simplified example makes it easier to read and keeps the user focused on the task at hand. Let me know what you think |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @macolso - I agree that this flows better - unfortunately I did get confused at one point, and spotted a couple of what I think were typos arising from the previous reuse of names. I may be wrong though...
|
|
||
| We'll go ahead add a path that will be used our cron job in later steps: | ||
|
|
||
| ```toml |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to add a second trigger? Is this trying to illustrate a recommended practice? It would be good to say more about the motivation because right now this feels like a step I follow without knowing why.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went back and forth on this... I decided to not add a second trigger to keep the example simple. Perhaps I can write a more realistic example for Spin Hub that we can link as a resource at the end of the tutorial for those interested in that scenario.
To simplify things, I've removed the specific path and replaced it with wildcard.
| component = "hello-cron-job" | ||
| ``` | ||
|
|
||
| > Note that you can have multiple cron jobs per Spin application as long as the combination of schedule and path_and_query is unique. We will review how to set those values later in the tutorial. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems a bit disconnected from "add a trigger." It feels like you're setting up for a mental model of "multiple cron jobs per app, each cron job handled by a different component, those components on different triggers, cron jobs mapped to components via their routes" but it's not explicit, and the "each trigger points at the same component as the everything route and we route within the component" doesn't draw out that structure.
Perhaps move this down to where you talk about creating cron jobs, and if you want to talk about how to structure a multi-job app then do so there? And focus on the simple "get something working" path here? Or do you feel that leads readers to a dead end?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed - I've moved it down to the section where I talk about the required parameters for the spin aka crons create subcommand. I decided to not expand into multi-job to keep the tutorial manageable, but I like the idea of creating a more complex example for Spin Hub or fwf-examples we can link to in this tutorial for those wanting a more realistic example.
|
|
||
| * **Schedule** – How often the job runs, in standard cron syntax | ||
| * **Path and query** – The HTTP path (and optional query parameters) to invoke | ||
| * **Name** – A name for your cron job (this will be associated with the Spin application in your current working directory) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider breaking this up - "it applies to the app in your current directory" is important enough that it shouldn't be a parenthesis under "the name for the job". E.g.
| * **Name** – A name for your cron job (this will be associated with the Spin application in your current working directory) | |
| * **Name** – A name for your cron job | |
| The cron job will always invoke the Spin application in your current working directory. |
(or perhaps "...will always invoke the Spin application deployed from your current..." which avoids any implication that it will invoke it in your cwd, but is perhaps awkward and requires extra effort for the reader to parse, not sure)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point about highlighting this. I removed it from parenthesis and put it at the beginning of the paragraph for this section.
| +----------------+--------------+-------------------------+ | ||
| | Name | Schedule | Next Run | | ||
| +=========================================================+ | ||
| | hello-cron-job | */5 * * * * | 2025-04-02 04:00:00 UTC | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| | hello-cron-job | */5 * * * * | 2025-04-02 04:00:00 UTC | | |
| | cron-job-1 | */5 * * * * | 2025-04-02 04:00:00 UTC | |
or wait, are you saying this is the app name rather than the job name?
(I am not sure if the command shows all cron jobs or only the ones associated with the current app.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
d'oh - typo! I fixed this. I also renamed the app to "hello-world" to avoid confusion between app name and cron job name.
I am not sure if the command shows all cron jobs or only the ones associated with the current app.)
@rylev any guidance on this? I'm not sure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having thoroughly distinct different names for the app and the cron job is an excellent idea - thank you!
…s down, fixed cron typo Signed-off-by: macolso <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me. I'm happy to defer the "does it list all jobs or current app's jobs" if you want to get this done and dusted, it's a fairly minor detail and we can always add it later if the spirit moves us. (Although it may be worth waiting for Ryan anyway!) Thanks for your patience through the review cycles!
Co-authored-by: itowlson <[email protected]> Signed-off-by: MacKenzie Olson <[email protected]>
Thanks for all the polish help! Between writing most of this at conferences or on plane, it definitely needed the help... I will go ahead and merge and we can add the "does it list all jobs or current app's jobs" later. I think it would be helpful to maybe even include an article about the purpose of that config file in our docs since it's a bit of an "insider knowledge" resource ATM. |
Content must go through a pre-merge checklist.
Resolves https://github.com/fermyon/a3000-docs/issues/228
Blocked on #1514
Pre-Merge Content Checklist
This documentation has been checked to ensure that:
title,template, anddateare all settemplates/*.hbsfiles) that points to a document.mdthat is set to publish in the future? If so please only publish the.mdand.hbschanges in real-time (otherwise there will be a menu item pointing to a.mdfile that does not exist)cat -ve <filename> | grep $'\r' | wc -land expect 0 as a result)bart checkPREVIEW_MODE=1and runnpm run stylesto update styling)npm run testand resolved all errors