-
Notifications
You must be signed in to change notification settings - Fork 90
docs: Rework the Scheduling section for 4.0 #719
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
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
98977f2
docs: Rework the Scheduling section for 4.0
developerjamiu 388ff95
docs: Address self-review feedback on the scheduling section
developerjamiu 658b26a
Merge remote-tracking branch 'origin/main' into concepts-phase3-secti…
developerjamiu a62ff17
docs: Address review feedback on the scheduling section
developerjamiu 0a88146
docs: Use a straight apostrophe in the inheritance description
developerjamiu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| --- | ||
| description: Future calls schedule work to run later, on a delay, at a set time, or on a repeating schedule, persisted in the database so they survive restarts. | ||
| --- | ||
|
|
||
| # Overview | ||
|
|
||
| A future call is a piece of server work you schedule to run later instead of right now. You pick a method, say when it should run, and Serverpod invokes it at that time, even if the request that scheduled it has long since finished. Common uses are a welcome email an hour after sign-up, a reminder a day before an appointment, or a cleanup job that runs every night. | ||
|
|
||
| Future calls are stored in the database, so they survive a server restart and are shared across every server instance you run. This makes them different from an in-memory `Timer`: a scheduled call is not lost if the process that created it stops. | ||
|
|
||
| ## What you can schedule | ||
|
|
||
| You write a future call as a method on a class, generate the type-safe code, and then schedule it in one of three ways: | ||
|
|
||
| - **After a delay**, for example one hour from now. | ||
| - **At a specific time**, for example a fixed date and time in the future. | ||
| - **On a repeating schedule**, either a fixed interval (every 20 minutes) or a [cron](https://en.wikipedia.org/wiki/Cron) expression (every day at 02:00 UTC). Cron is a standard text format for describing repeating schedules. | ||
|
|
||
| ## Execution guarantees | ||
|
|
||
| A scheduled call runs **at least once**. Across all your running server instances, one instance claims each call and normally runs it a single time. If that instance crashes partway through, the call is picked up and run again by another instance, so a call can occasionally run more than once. Write work that is safe to repeat (for example, check whether the email was already sent before sending it). | ||
|
|
||
| If the method itself throws an exception, Serverpod logs the error and does not retry the call. You are responsible for retrying failed work: schedule a new call if the work needs to happen. Recurring calls are the exception, since the next run is always scheduled regardless of whether the current one succeeds. | ||
|
|
||
| ## Where future calls run | ||
|
|
||
| Which servers run future calls depends on their role, the mode a server is started in. Servers in the default `monolith` role run them, and future calls need a database. A server started in the `serverless` role does not run them. If you host in a serverless environment, run a separate scheduled process in the `maintenance` role to execute due calls. See [server roles](../server-fundamentals/running-your-server#choose-a-server-role) and [hosting elsewhere](../../deployments/custom-hosting/hosting-elsewhere). | ||
|
|
||
| ## What each page covers | ||
|
|
||
| - **[Future calls](future-calls)**: define a future call, schedule it after a delay or at a time, and cancel scheduled calls. | ||
| - **[Recurring tasks](recurring-tasks)**: run a call on a repeating cron or interval schedule. | ||
| - **[Inheritance](inheritance)**: extend future calls from other classes and modules. | ||
| - **[Configuration](configuration)**: set concurrency, the scan interval, and broken-call handling. | ||
| - **[Legacy](legacy)**: the older string-based API, kept for existing code. | ||
|
|
||
| ## Related | ||
|
|
||
| - [Sessions](../endpoints-and-apis/sessions): the session a future call receives when it runs. | ||
| - [Server roles](../server-fundamentals/running-your-server#choose-a-server-role): which roles run scheduled work. | ||
| - [Configuration reference](../lookups/configuration-reference): every future-call key with its environment variable. |
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| --- | ||
| description: A future call is a method Serverpod runs later, scheduled after a delay or at a specific time, and cancellable by identifier. | ||
| --- | ||
|
|
||
| # Future calls | ||
|
|
||
| A future call is a method that Serverpod runs later. You define it on a class, generate the type-safe code, and schedule it from anywhere you have access to the server. This page covers the one-off cases: run once after a delay, or once at a specific time. For repeating schedules, see [Recurring tasks](recurring-tasks). | ||
|
|
||
| ## Define a future call | ||
|
|
||
| Extend the `FutureCall` class and add the methods you want to invoke later. | ||
|
|
||
| ```dart | ||
| import 'package:serverpod/serverpod.dart'; | ||
|
|
||
| class ExampleFutureCall extends FutureCall { | ||
| Future<void> doWork(Session session) async { | ||
| // Do something interesting in the future here. | ||
| } | ||
|
|
||
| Future<void> doOtherWork(Session session, String data) async { | ||
| // Do something interesting in the future here. | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| Each method must: | ||
|
|
||
| - Return `Future<void>`. | ||
| - Take a [`Session`](../endpoints-and-apis/sessions) as its first parameter. | ||
| - Use only [serializable types](../data-and-the-database/models) for any other parameters. Typed `List`, `Map`, `Set`, and Dart records are allowed, but streams are not. | ||
|
|
||
| Generate the code for your future calls. With `serverpod start` running, saving the file regenerates the code. Outside a session, run `serverpod generate`. | ||
|
|
||
| This creates a type-safe interface in your server's `lib/src/generated/future_calls.dart` file, reachable from the `Serverpod` object as `pod.futureCalls`. You do not register these calls yourself. Serverpod does it for you when the server starts, so your `server.dart` needs no future-call setup: | ||
|
|
||
| ```dart | ||
| import 'package:serverpod/serverpod.dart'; | ||
|
|
||
| import 'src/generated/protocol.dart'; | ||
| import 'src/generated/endpoints.dart'; | ||
|
|
||
| void run(List<String> args) async { | ||
| final pod = Serverpod( | ||
| args, | ||
| Protocol(), | ||
| Endpoints(), | ||
| ); | ||
|
|
||
| await pod.start(); | ||
| } | ||
| ``` | ||
|
|
||
| :::note | ||
| The `pod.futureCalls` accessor exists only once you have defined at least one future call and generated the code. | ||
| ::: | ||
|
|
||
| :::warning | ||
| Scheduling a call before the server has started throws an exception, so schedule from an endpoint or after `pod.start()` rather than while building the server. | ||
| ::: | ||
|
|
||
| ## Schedule a call | ||
|
|
||
| Schedule a call by chaining the timing method, the accessor for your class, and the method to invoke. The accessor is your class name with the first letter lowercased and a trailing `FutureCall` removed, so `ExampleFutureCall` becomes `example`. | ||
|
|
||
| Run a call one hour from now with `callWithDelay`: | ||
|
|
||
| ```dart | ||
| await pod.futureCalls | ||
| .callWithDelay(const Duration(hours: 1)) | ||
| .example | ||
| .doWork(); | ||
| ``` | ||
|
|
||
| Run a call at a specific time with `callAtTime`: | ||
|
|
||
| ```dart | ||
| await pod.futureCalls | ||
| .callAtTime(DateTime(2030, 1, 1)) | ||
| .example | ||
| .doOtherWork('1'); | ||
| ``` | ||
|
|
||
| The call runs at the exact instant you pass. A `DateTime` denotes an absolute moment, so `DateTime(2030, 1, 1)` schedules the call for midnight in the server's local time. Pass a UTC value, such as `DateTime.utc(2030, 1, 1)`, if you want the numbers to be read as UTC. | ||
|
|
||
| ### Schedule from an endpoint | ||
|
|
||
| Inside an endpoint you reach the server through `session.serverpod`, so you can schedule a call in response to a request: | ||
|
|
||
| ```dart | ||
| class OrderEndpoint extends Endpoint { | ||
| Future<void> placeOrder(Session session, Order order) async { | ||
| // ... store the order ... | ||
|
|
||
| // Send a follow-up an hour from now. | ||
| await session.serverpod.futureCalls | ||
| .callWithDelay(const Duration(hours: 1)) | ||
| .example | ||
| .doWork(); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Cancel scheduled calls | ||
|
|
||
| Give a call an `identifier` when you schedule it so you can cancel it later. The same identifier can be applied to several calls. | ||
|
|
||
| ```dart | ||
| await pod.futureCalls | ||
| .callWithDelay( | ||
| const Duration(hours: 1), | ||
| identifier: 'an-identifying-string', | ||
| ) | ||
| .example | ||
| .doWork(); | ||
| ``` | ||
|
|
||
| Cancel every not-yet-run call that shares an identifier: | ||
|
|
||
| ```dart | ||
| await pod.futureCalls.cancel('an-identifying-string'); | ||
| ``` | ||
|
|
||
| Calls that share an identifier run independently. The identifier only groups them so you can cancel them together, and cancelling affects only calls that have not run yet. | ||
|
|
||
| ## Inspect scheduled calls | ||
|
|
||
| Scheduled calls are stored in the `serverpod_future_call` database table. You can query it to see what is pending, which helps when debugging why a call did or did not run. | ||
|
|
||
| ## Execution timeout | ||
|
|
||
| Future calls have no execution timeout: a call runs until its method returns. If a call needs a time limit, enforce it inside the method yourself, for example with `Future.timeout` around the work. | ||
|
|
||
| ## Related | ||
|
|
||
| - [Recurring tasks](recurring-tasks): run a call on a repeating schedule. | ||
| - [Configuration](configuration): concurrency, scan interval, and broken-call handling. | ||
| - [Sessions](../endpoints-and-apis/sessions): the session a future call receives when it runs. | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.