-
Notifications
You must be signed in to change notification settings - Fork 78
docs: Type-safe code generated interface for future calls #390
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
marcelomendoncasoares
merged 5 commits into
serverpod:main
from
Crazelu:feat/type-safe-future-calls
Jan 20, 2026
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
8cc866c
docs: Type-safe code generated interface for future calls
Crazelu 7837728
docs: Updates future calls documentation
Crazelu 401e2f7
docs: Adds info notes for future call inheritance and UTC timezone re…
Crazelu c2056f5
Merge commit '6f4be35b4617e254bb2e29c7801159831c27fb2c' into feat/typ…
marcelomendoncasoares 34323f1
chore: Copy the docs over to the version 3.2.0
marcelomendoncasoares 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 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,103 @@ | ||
| # Setup | ||
|
|
||
| Serverpod supports scheduling future work with the `future call` feature. Future calls are calls that will be invoked at a later time. An example is if you want to send a drip-email campaign after a user signs up. You can schedule a future call for a day, a week, a month, or a [recurring interval](recurring-task). The calls are stored in the database, so they will persist even if the server is restarted. | ||
|
|
||
| A future call is guaranteed to only execute once across all your instances that are running, but execution failures are not handled automatically. It is your responsibility to schedule a new future call if the work was not able to complete. | ||
|
|
||
| To create future calls, extend the `FutureCall` class and define the methods you wish to invoke at a later time. | ||
|
|
||
| ```dart | ||
| import 'package:serverpod/serverpod.dart'; | ||
|
|
||
| class ExampleFutureCall extends FutureCall { | ||
| Future<void> doWork(Session session, String data) async { | ||
| // Do something interesting in the future here. | ||
| } | ||
|
|
||
| Future<void> doOtherWork(Session session, String data) async { | ||
| // Do something interesting in the future here. | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| :::info | ||
| For a method to be recognized by Serverpod as a future call, it must return a `Future<void>` and take at least two parameters. The first parameter must be a [`Session`](../sessions) object. You can pass any serializable types as other parameters, and even use `List`, `Map`, `Set` or Dart records as long as they are typed. `Streaming` parameters are not supported. | ||
| ::: | ||
|
|
||
| Next, you need to generate the code for your future calls: | ||
|
|
||
| ```bash | ||
| $ serverpod generate | ||
| ``` | ||
|
|
||
| `serverpod generate` will create a type-safe interface for invoking the future calls in the server's `generated/future_calls.dart` file. This interface can be accessed from the Serverpod object. | ||
|
|
||
| The future calls you create are registered by `Serverpod` after the server starts. | ||
|
|
||
| ```dart | ||
| import 'package:serverpod/serverpod.dart'; | ||
| import 'package:serverpod_auth_idp_server/core.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(); | ||
| } | ||
| ``` | ||
|
|
||
| You are now able to schedule future calls to be invoked in the future by calling either `callWithDelay` or `callAtTime` depending on your needs. | ||
|
|
||
| :::warning | ||
| Scheduling a future call before the server starts will lead to exceptions. | ||
| ::: | ||
|
|
||
| Invoke a future call 1 hour from now by calling `callWithDelay`. | ||
|
|
||
| ```dart | ||
| await pod.futureCalls | ||
| .callWithDelay(const Duration(hours: 1)) | ||
| .example | ||
| .doWork('1'); | ||
| ``` | ||
|
|
||
| Invoke a future call at a specific time and/or date in the future by calling `callAtTime`. | ||
|
|
||
| ```dart | ||
| await pod.futureCalls | ||
| .callAtTime(DateTime(2026, 1, 1)) | ||
| .example | ||
| .doOtherWork('2'); | ||
| ``` | ||
|
|
||
| :::info | ||
| Scheduling a future call at a specific time/date will always resolve the `DateTime` to UTC. | ||
| ::: | ||
|
|
||
| When scheduling a future call, it is also possible to give it an `identifier` so that it can be referenced later. The same identifier can be applied to multiple future calls. | ||
|
|
||
| ```dart | ||
| await pod.futureCalls | ||
| .callWithDelay( | ||
| const Duration(hours: 1), | ||
| identifier: 'an-identifying-string', | ||
| ) | ||
| .example | ||
| .doWork('1'); | ||
| ``` | ||
|
|
||
| This identifier can then be used to cancel all future calls scheduled with said identifier. | ||
|
|
||
| ```dart | ||
| await pod.futureCalls.cancel('an-identifying-string'); | ||
| ``` | ||
|
|
||
| :::info | ||
| The future call feature is not enabled when running Serverpod in serverless mode. | ||
| ::: | ||
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,71 @@ | ||
| # Recurring Task | ||
|
|
||
| The recommended way to achieve cron-like scheduling is by scheduling a future call inside another. | ||
| To set this up, extend the `FutureCall` class and define two methods. | ||
|
|
||
| ```dart | ||
| import 'package:serverpod/serverpod.dart'; | ||
|
|
||
| class ExampleFutureCall extends FutureCall { | ||
| Future<void> doWork(Session session, int input) async { | ||
| await _doWork(session, input); | ||
| } | ||
|
|
||
| Future<void> _doWork(Session session, int input) async { | ||
| session.log('Working with input $input'); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| Next, generate the code for your future call: | ||
|
|
||
| ```bash | ||
| $ serverpod generate | ||
| ``` | ||
|
|
||
| :::info | ||
| Code is only generated for the public method while the private method contains the logic to be invoked as a recurring task. | ||
| ::: | ||
|
|
||
| Next, import the generated `endpoints.dart` file and schedule the recurring future call using the generated code: | ||
|
|
||
| ```dart | ||
| import 'package:serverpod/serverpod.dart'; | ||
| import 'generated/endpoints.dart'; | ||
|
|
||
| class ExampleFutureCall extends FutureCall { | ||
| Future<void> doWork(Session session, int input) async { | ||
| await session.serverpod.futureCalls | ||
| .callWithDelay(const Duration(minutes: 20)) | ||
| .example | ||
| .doWork(input + 1); | ||
|
|
||
| await _doWork(session, input); | ||
| } | ||
|
|
||
| Future<void> _doWork(Session session, int input) async { | ||
| session.log('Working with input $input'); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| Now when you schedule the `doWork` future call, it will continously invoke `_doWork` at an interval of 20 minutes. | ||
|
|
||
| ```dart | ||
| import 'package:serverpod/serverpod.dart'; | ||
| import 'package:serverpod_auth_idp_server/core.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(); | ||
| await pod.futureCalls.callWithDelay(Duration(minutes: 20)).example.doWork(2); | ||
| } | ||
| ``` |
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.