Bladeren bron

docs(core): Add docs on scheduled tasks

Michael Bromley 9 maanden geleden
bovenliggende
commit
31c6eba1e3
39 gewijzigde bestanden met toevoegingen van 1072 en 106 verwijderingen
  1. 233 80
      docs/docs/guides/developer-guide/scheduled-tasks/index.md
  2. 12 0
      docs/docs/reference/graphql-api/admin/input-types.md
  3. 9 0
      docs/docs/reference/graphql-api/admin/mutations.md
  4. 26 0
      docs/docs/reference/graphql-api/admin/object-types.md
  5. 9 0
      docs/docs/reference/graphql-api/admin/queries.md
  6. 36 0
      docs/docs/reference/graphql-api/shop/object-types.md
  7. 24 0
      docs/docs/reference/graphql-api/shop/queries.md
  8. 1 1
      docs/docs/reference/typescript-api/assets/asset-options.md
  9. 1 1
      docs/docs/reference/typescript-api/auth/auth-options.md
  10. 1 1
      docs/docs/reference/typescript-api/auth/cookie-options.md
  11. 1 1
      docs/docs/reference/typescript-api/auth/superadmin-credentials.md
  12. 1 1
      docs/docs/reference/typescript-api/common/permission.md
  13. 1 1
      docs/docs/reference/typescript-api/configuration/api-options.md
  14. 1 1
      docs/docs/reference/typescript-api/configuration/entity-options.md
  15. 7 1
      docs/docs/reference/typescript-api/configuration/runtime-vendure-config.md
  16. 1 1
      docs/docs/reference/typescript-api/configuration/system-options.md
  17. 7 1
      docs/docs/reference/typescript-api/configuration/vendure-config.md
  18. 1 1
      docs/docs/reference/typescript-api/import-export/import-export-options.md
  19. 1 1
      docs/docs/reference/typescript-api/job-queue/job-queue-options.md
  20. 1 1
      docs/docs/reference/typescript-api/orders/order-options.md
  21. 1 1
      docs/docs/reference/typescript-api/payment/payment-options.md
  22. 1 1
      docs/docs/reference/typescript-api/products-stock/catalog-options.md
  23. 1 1
      docs/docs/reference/typescript-api/promotions/promotion-options.md
  24. 44 0
      docs/docs/reference/typescript-api/scheduled-tasks/clean-sessions-task.md
  25. 83 0
      docs/docs/reference/typescript-api/scheduled-tasks/default-scheduler-plugin.md
  26. 68 0
      docs/docs/reference/typescript-api/scheduled-tasks/default-scheduler-strategy.md
  27. 14 0
      docs/docs/reference/typescript-api/scheduled-tasks/index.md
  28. 164 0
      docs/docs/reference/typescript-api/scheduled-tasks/scheduled-task.md
  29. 41 0
      docs/docs/reference/typescript-api/scheduled-tasks/scheduler-options.md
  30. 54 0
      docs/docs/reference/typescript-api/scheduled-tasks/scheduler-service.md
  31. 119 0
      docs/docs/reference/typescript-api/scheduled-tasks/scheduler-strategy.md
  32. 23 5
      docs/docs/reference/typescript-api/services/session-service.md
  33. 1 1
      docs/docs/reference/typescript-api/shipping/shipping-options.md
  34. 1 1
      docs/docs/reference/typescript-api/tax/tax-options.md
  35. 4 2
      packages/core/src/plugin/default-scheduler-plugin/default-scheduler.plugin.ts
  36. 1 0
      packages/core/src/plugin/default-scheduler-plugin/types.ts
  37. 18 1
      packages/core/src/scheduler/scheduled-task.ts
  38. 34 0
      packages/core/src/scheduler/scheduler-strategy.ts
  39. 26 0
      packages/core/src/scheduler/tasks/clean-sessions-task.ts

+ 233 - 80
docs/docs/guides/developer-guide/scheduled-tasks/index.md

@@ -1,9 +1,9 @@
 ---
 ---
-title: "Scheduled Tasks"
+title: 'Scheduled Tasks'
 showtoc: true
 showtoc: true
 ---
 ---
 
 
-Scheduled tasks are a way of executing some code at pre-defined intervals. There are many examples of work that can be done using scheduled tasks, 
+Scheduled tasks are a way of executing some code at pre-defined intervals. There are many examples of work that can be done using scheduled tasks,
 such as:
 such as:
 
 
 - Generating a sitemap
 - Generating a sitemap
@@ -11,131 +11,284 @@ such as:
 - Sending abandoned cart emails
 - Sending abandoned cart emails
 - Cleaning up old data
 - Cleaning up old data
 
 
-In Vendure you can create scheduled tasks by defining a [standalone script](/guides/developer-guide/stand-alone-scripts/) which can then 
-be executed via any scheduling mechanism you like, such as a cron job or similar mechanism provided by your hosting provider.
+Since Vendure v3.3, there is a built-in mechanism which allows you to define scheduled tasks in a convenient and powerful way.
 
 
-## Creating a Scheduled Task
+:::info
+All the information on page applies to Vendure v3.3+
+
+For older versions, there is no built-in support for scheduled tasks, but you can
+instead use a [stand-alone script](/guides/developer-guide/stand-alone-scripts/) triggered by a cron job.
+:::
+
+## Setting up the DefaultSchedulerPlugin
 
 
-Let's imagine that you have created a plugin that exposes a `SitemapService` which generates a sitemap for your store. You want to run this
-task every night at midnight. 
+In your Vendure config, import and add the [DefaultSchedulerPlugin](/reference/typescript-api/scheduled-tasks/default-scheduler-plugin) to your
+plugins array. If you created your project with a version newer than v3.3, this should already be configured.
 
 
-First we need to create a standalone script which will run the task. This script will look something like this:
+```ts title="vendure-config.ts"
+import { DefaultSchedulerPlugin, VendureConfig } from '@vendure/core';
 
 
-```ts title="scheduled-tasks.ts"
-import { bootstrapWorker, Logger, RequestContextService } from '@vendure/core';
-import { SitemapService } from './plugins/sitemap';
+export const config: VendureConfig = {
+    // ...
+    plugins: [DefaultSchedulerPlugin.init()],
+};
+```
+
+When you first add this plugin to your config, you'll need to [generate a migration](/guides/developer-guide/migrations/) because the
+plugin will make use of a new database table in order to guarantee only-once execution of tasks.
 
 
-import { config } from './vendure-config';
+You can then start adding tasks. Vendure ships with a task that will clean up old sessions from the database.
+
+:::note
+The `cleanSessionsTask` task is actually configured by default from v3.3+, so normally you won't have to specify this
+manually unless you wish to change any of the default configuration using the `.configure()` method.
+:::
 
 
-if (require.main === module) {
-    generateSitemap()
-        .then(() => process.exit(0))
-        .catch(err => {
-            Logger.error(err);
-            process.exit(1);
+```ts title="vendure-config.ts"
+import { cleanSessionsTask, DefaultSchedulerPlugin, VendureConfig } from '@vendure/core';
+
+export const config: VendureConfig = {
+    // ...
+    schedulerOptions: {
+        tasks: [
+            // Use the task as is
+            cleanSessionsTask,
+            // or further configure the task
+            cleanSessionsTask.configure({
+                // Run the task every day at 3:00am
+                // The default schedule is every day at 00:00am
+                schedule: cron => cron.everyDayAt(3, 0),
+                params: {
+                    // How many sessions to process in each batch
+                    // Default: 10_000
+                    batchSize: 5_000,
+                },
+            }),
+        ],
+    },
+    plugins: [DefaultSchedulerPlugin.init()],
+};
+```
+
+## Creating a Scheduled Task
+
+Let's imagine that you have created a `SitemapPlugin` that exposes a `SitemapService` which generates a sitemap for your store. You want to run this
+task every night at midnight.
+
+Inside the plugin, you would first define a new [ScheduledTask](/reference/typescript-api/scheduled-tasks/scheduled-task) instance:
+
+```ts title="/plugins/sitemap/config/generate-sitemap-task.ts"
+import { ScheduledTask, RequestContextService } from '@vendure/core';
+
+import { SitemapService } from '../services/sitemap.service';
+
+export const generateSitemapTask = new ScheduledTask({
+    // Give your task a unique ID
+    id: 'generate-sitemap',
+    // A human-readable description of the task
+    description: 'Generates a sitemap file',
+    // Params can be used to further configure aspects of the
+    // task. They get passed in to the `execute` function as the
+    // second argument.
+    // They can be later modified using the `.configure()` method on the instance
+    params: {
+        shopBaseUrl: 'https://www.myshop.com',
+    },
+    // Define a default schedule. This can be modified using the
+    // `.configure()` method on the instance later.
+    schedule: cron => cron.everyDayAt(0, 0),
+    // This is the function that will be executed per the schedule.
+    async execute(injector, params) {
+        // Using `app.get()` we can grab an instance of _any_ provider defined in the
+        // Vendure core as well as by our plugins.
+        const sitemapService = app.get(SitemapService);
+
+        // For most service methods, we'll need to pass a RequestContext object.
+        // We can use the RequestContextService to create one.
+        const ctx = await app.get(RequestContextService).create({
+            apiType: 'admin',
         });
         });
-}
 
 
-async function generateSitemap() {
-    // This will bootstrap an instance of the Vendure Worker, providing
-    // us access to all of the services defined in the Vendure core.
-    // (but without the unnecessary overhead of the API layer).
-    const { app } = await bootstrapWorker(config);
-
-    // Using `app.get()` we can grab an instance of _any_ provider defined in the
-    // Vendure core as well as by our plugins.
-    const sitemapService = app.get(SitemapService);
-
-    // For most service methods, we'll need to pass a RequestContext object.
-    // We can use the RequestContextService to create one.
-    const ctx = await app.get(RequestContextService).create({
-        apiType: 'admin',
-    });
-    
-    await sitemapService.generateSitemap(ctx);
-
-    Logger.info(`Completed sitemap generation`);
-}
+        // Here's the actual work we want to perform.
+        const result = await sitemapService.generateSitemap(ctx);
+
+        // The return value from the `execute` function will be available
+        // as the `lastResult` property when viewing tasks.
+        return { result };
+    },
+});
 ```
 ```
 
 
-### Schedule the task
+## Using a task
+
+Now that the task has been defined, we need to tell Vendure to use it.
+
+To do so we need to add it to the [schedulerOptions.tasks](/reference/typescript-api/scheduled-tasks/scheduler-options#tasks) array.
+
+### Adding directly in Vendure config
+
+This can be done directly in your Vendure config file:
+
+```ts title="vendure-config.ts"
+import { cleanSessionsTask, DefaultSchedulerPlugin, VendureConfig } from '@vendure/core';
+
+// highlight-next-line
+import { SitemapPlugin, generateSitemapTask } from './plugins/sitemap';
+
+export const config: VendureConfig = {
+    // ...
+    schedulerOptions: {
+        tasks: [
+            cleanSessionsTask,
+            // highlight-start
+            // Here's an example of overriding the
+            // default params using the `configure()` method.
+            generateSitemapTask.configure({
+                params: {
+                    shopBaseUrl: 'https://www.shoes.com'
+                }
+            }),
+            // highlight-end
+        ],
+    },
+    plugins: [
+        // highlight-next-line
+        SitemapPlugin,
+        DefaultSchedulerPlugin.init()
+    ],
+};
+```
 
 
-Each hosting provider has its own way of scheduling tasks. A common way is to use a cron job. 
-For example, to run the above script every night at midnight, you could add the following line to your crontab:
+### Adding in plugin configuration function
+
+An alternative is that a plugin can automatically add the task to the config using the
+plugin's [configuration function](/reference/typescript-api/plugin/vendure-plugin-metadata#configuration), which allows plugins to alter the Vendure config.
+
+This allows a plugin to encapsulate any scheduled tasks so that the plugin consumer only needs to add the plugin, and not worry about
+separately adding the task to the tasks array.
+
+```ts title="src/plugins/sitemap/sitemap.plugin.ts"
+import { VendurePlugin, PluginCommonModule, Type, ScheduledTask, VendureConfig } from '@vendure/core';
+
+import { PLUGIN_OPTIONS } from './constants';
+import { SitemapPluginOptions } from './types';
+import { SitemapService } from './services/sitemap.service';
+import { generateSitemapTask } from './config/generate-sitemap-task';
+
+@VendurePlugin({
+    imports: [PluginCommonModule],
+    providers: [SitemapService],
+    configuration: (config: VendureConfig) => {
+        // highlight-start
+        // Add the task to the schedulerOptions.tasks array
+        config.schedulerOptions.tasks.push(
+            generateSitemapTask.configure({
+                params: {
+                    shopBaseUrl: SitemapPlugin.options.shopBaseUrl,
+                }
+            })
+        );
+        // highlight-end
+        return config;
+    },
+})
+export class SitemapPlugin {
+    static options: SitemapPluginOptions;
+
+    static init(options?: SitemapPluginOptions) {
+        this.options = {
+            shopBaseUrl: '',
+            ...(options ?? {}),
+        }
+    }
+}
+```
 
 
-```bash
-0 0 * * * node /path/to/scheduled-tasks.js
+This plugin can now be consumed like this:
+
+```ts title="vendure-config.ts"
+import { DefaultSchedulerPlugin, VendureConfig } from '@vendure/core';
+
+// highlight-next-line
+import { SitemapPlugin } from './plugins/sitemap';
+
+export const config: VendureConfig = {
+    // ...
+    plugins: [
+        // highlight-start
+        SitemapPlugin.init({
+            shopBaseUrl: 'https://www.shoes.com'
+        }),
+        // highlight-end
+        DefaultSchedulerPlugin.init()
+    ],
+};
 ```
 ```
 
 
-This will run the script `/path/to/scheduled-tasks.js` every night at midnight.
+## How scheduled tasks work
 
 
-### Long-running tasks
+The key problems solved by Vendure's task scheduler are:
 
 
-What if the scheduled task does a significant amount of work that would take many minutes to complete? In this case
-you should consider using the [job queue](/guides/developer-guide/worker-job-queue/#using-job-queues-in-a-plugin) to
-execute the work on the worker.
+- Ensuring that a task is only run a single time per scheduled execution, even when you have multiple instances of servers and workers running.
+- Keeping scheduled task work away from the server instances, so that it does not affect API responsiveness.
 
 
-Taking the above example, let's now imagine that the `SitemapService` exposes a `triggerGenerate()` method which
-adds a new job to the job queue. The job queue will then execute the task in the background, allowing the scheduled
-task to complete quickly.
+The first problem is handled by the [SchedulerStrategy](/reference/typescript-api/scheduled-tasks/scheduler-strategy), which implements a locking
+mechanism to ensure that the task is executed only once.
 
 
-```ts title="scheduled-tasks.ts"
-import { bootstrapWorker, Logger, RequestContextService } from '@vendure/core';
-import { SitemapService } from './plugins/sitemap';
+The second problem is handled by having tasks only executed on worker processes.
 
 
-import { config } from './vendure-config';
+## Scheduled tasks vs job queue
 
 
-if (require.main === module) {
-    generateSitemap()
-        .then(() => process.exit(0))
-        .catch(err => {
-            Logger.error(err);
-            process.exit(1);
-        });
-}
+There is some overlap between the use of a scheduled task and a [job queue job](/guides/developer-guide/worker-job-queue/). They both perform some
+task on the worker, independent of requests coming in to the server.
 
 
-async function generateSitemap() {
-    const { app } = await bootstrapWorker(config);
-    const sitemapService = app.get(SitemapService);
-    const ctx = await app.get(RequestContextService).create({
-        apiType: 'admin',
-    });
-    
-    await sitemapService.triggerGenerate(ctx);
+The first difference is that jobs must be triggered explicitly, whereas scheduled tasks are triggered automatically according to the schedule.
 
 
-    Logger.info(`Sitemap generation triggered`);
-}
-```
+Secondly, jobs are put in a _queue_ and executed once any prior pending jobs have been processed. On the other hand, scheduled tasks are executed
+as soon as the schedule dictates.
+
+It is possible to combine the two: namely, you can define a scheduled task which adds a job to the job queue. This is, for instance, how the
+built-in [cleanSessionsTask](/reference/typescript-api/scheduled-tasks/clean-sessions-task) works. This pattern is something you should
+consider if the scheduled task may take a significant amount of time or resources and you want to let the job queue manage that.
+
+It also has the advantage of giving you a record of results for that work that has been put on the job queue, whereas scheduled tasks
+only record that result of the last execution.
 
 
-## Using @nestjs/schedule
 
 
-NestJS provides a [dedicated package for scheduling tasks](https://docs.nestjs.com/techniques/task-scheduling), called `@nestjs/schedule`. 
+## A note on @nestjs/schedule
+
+NestJS provides a [dedicated package for scheduling tasks](https://docs.nestjs.com/techniques/task-scheduling), called `@nestjs/schedule`.
 
 
 You can also use this approach to schedule tasks, but you need to aware of a very important caveat:
 You can also use this approach to schedule tasks, but you need to aware of a very important caveat:
 
 
 :::warning
 :::warning
 When using `@nestjs/schedule`, any method decorated with the `@Cron()` decorator will run
 When using `@nestjs/schedule`, any method decorated with the `@Cron()` decorator will run
-on _all_ instances of the application. This means it will run on the server _and_ on the 
+on _all_ instances of the application. This means it will run on the server _and_ on the
 worker. If you are running multiple instances, then it will run on all instances.
 worker. If you are running multiple instances, then it will run on all instances.
+
+This is the specific issue solved by the built-in ScheduledTask system described above.
+Therefore it is not recommended to use the `@nestjs/schedule` package under normal
+circumstances.
 :::
 :::
 
 
-You can, for instance, inject the ProcessContext into the service and check if the current instance is the worker or the server.
+You can, for instance, inject the [ProcessContext](/reference/typescript-api/common/process-context) into the service and check if the current instance is the worker or the server.
 
 
 ```ts
 ```ts
 import { Injectable } from '@nestjs/common';
 import { Injectable } from '@nestjs/common';
 import { Cron } from '@nestjs/schedule';
 import { Cron } from '@nestjs/schedule';
 
 
-
 @Injectable()
 @Injectable()
 export class SitemapService {
 export class SitemapService {
     constructor(private processContext: ProcessContext) {}
     constructor(private processContext: ProcessContext) {}
 
 
     @Cron('0 0 * * *')
     @Cron('0 0 * * *')
     async generateSitemap() {
     async generateSitemap() {
+        // highlight-start
         if (this.processContext.isWorker) {
         if (this.processContext.isWorker) {
             // Only run on the worker
             // Only run on the worker
             await this.triggerGenerate();
             await this.triggerGenerate();
         }
         }
+        // highlight-end
     }
     }
 }
 }
 ```
 ```

+ 12 - 0
docs/docs/reference/graphql-api/admin/input-types.md

@@ -4321,6 +4321,18 @@ import MemberDescription from '@site/src/components/MemberDescription';
 <div class="graphql-code-line ">channelIds: [<a href="/reference/graphql-api/admin/object-types#id">ID</a>!]</div>
 <div class="graphql-code-line ">channelIds: [<a href="/reference/graphql-api/admin/object-types#id">ID</a>!]</div>
 
 
 
 
+<div class="graphql-code-line top-level">&#125;</div>
+</div>
+
+## UpdateScheduledTaskInput
+
+<div class="graphql-code-block">
+<div class="graphql-code-line top-level">input <span class="graphql-code-identifier">UpdateScheduledTaskInput</span> &#123;</div>
+<div class="graphql-code-line ">id: <a href="/reference/graphql-api/admin/object-types#string">String</a>!</div>
+
+<div class="graphql-code-line ">enabled: <a href="/reference/graphql-api/admin/object-types#boolean">Boolean</a></div>
+
+
 <div class="graphql-code-line top-level">&#125;</div>
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
 </div>
 
 

+ 9 - 0
docs/docs/reference/graphql-api/admin/mutations.md

@@ -1838,6 +1838,15 @@ import MemberDescription from '@site/src/components/MemberDescription';
 <div class="graphql-code-line ">updateRole(input: <a href="/reference/graphql-api/admin/input-types#updateroleinput">UpdateRoleInput</a>!): <a href="/reference/graphql-api/admin/object-types#role">Role</a>!</div>
 <div class="graphql-code-line ">updateRole(input: <a href="/reference/graphql-api/admin/input-types#updateroleinput">UpdateRoleInput</a>!): <a href="/reference/graphql-api/admin/object-types#role">Role</a>!</div>
 
 
 
 
+<div class="graphql-code-line top-level">&#125;</div>
+</div>
+
+## updateScheduledTask
+<div class="graphql-code-block">
+<div class="graphql-code-line top-level">type <span class="graphql-code-identifier">Mutation</span> &#123;</div>
+<div class="graphql-code-line ">updateScheduledTask(input: <a href="/reference/graphql-api/admin/input-types#updatescheduledtaskinput">UpdateScheduledTaskInput</a>!): <a href="/reference/graphql-api/admin/object-types#scheduledtask">ScheduledTask</a>!</div>
+
+
 <div class="graphql-code-line top-level">&#125;</div>
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
 </div>
 
 

+ 26 - 0
docs/docs/reference/graphql-api/admin/object-types.md

@@ -3519,6 +3519,32 @@ import MemberDescription from '@site/src/components/MemberDescription';
 <div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
 <div class="graphql-code-line ">customFields: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
 
 
 
 
+<div class="graphql-code-line top-level">&#125;</div>
+</div>
+
+## ScheduledTask
+
+<div class="graphql-code-block">
+<div class="graphql-code-line top-level">type <span class="graphql-code-identifier">ScheduledTask</span> &#123;</div>
+<div class="graphql-code-line ">id: <a href="/reference/graphql-api/admin/object-types#string">String</a>!</div>
+
+<div class="graphql-code-line ">description: <a href="/reference/graphql-api/admin/object-types#string">String</a>!</div>
+
+<div class="graphql-code-line ">schedule: <a href="/reference/graphql-api/admin/object-types#string">String</a>!</div>
+
+<div class="graphql-code-line ">scheduleDescription: <a href="/reference/graphql-api/admin/object-types#string">String</a>!</div>
+
+<div class="graphql-code-line ">lastExecutedAt: <a href="/reference/graphql-api/admin/object-types#datetime">DateTime</a></div>
+
+<div class="graphql-code-line ">nextExecutionAt: <a href="/reference/graphql-api/admin/object-types#datetime">DateTime</a></div>
+
+<div class="graphql-code-line ">isRunning: <a href="/reference/graphql-api/admin/object-types#boolean">Boolean</a>!</div>
+
+<div class="graphql-code-line ">lastResult: <a href="/reference/graphql-api/admin/object-types#json">JSON</a></div>
+
+<div class="graphql-code-line ">enabled: <a href="/reference/graphql-api/admin/object-types#boolean">Boolean</a>!</div>
+
+
 <div class="graphql-code-line top-level">&#125;</div>
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
 </div>
 
 

+ 9 - 0
docs/docs/reference/graphql-api/admin/queries.md

@@ -517,6 +517,15 @@ import MemberDescription from '@site/src/components/MemberDescription';
 <div class="graphql-code-line ">roles(options: <a href="/reference/graphql-api/admin/input-types#rolelistoptions">RoleListOptions</a>): <a href="/reference/graphql-api/admin/object-types#rolelist">RoleList</a>!</div>
 <div class="graphql-code-line ">roles(options: <a href="/reference/graphql-api/admin/input-types#rolelistoptions">RoleListOptions</a>): <a href="/reference/graphql-api/admin/object-types#rolelist">RoleList</a>!</div>
 
 
 
 
+<div class="graphql-code-line top-level">&#125;</div>
+</div>
+
+## scheduledTasks
+<div class="graphql-code-block">
+<div class="graphql-code-line top-level">type <span class="graphql-code-identifier">Query</span> &#123;</div>
+<div class="graphql-code-line ">scheduledTasks: [<a href="/reference/graphql-api/admin/object-types#scheduledtask">ScheduledTask</a>!]!</div>
+
+
 <div class="graphql-code-line top-level">&#125;</div>
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
 </div>
 
 

+ 36 - 0
docs/docs/reference/graphql-api/shop/object-types.md

@@ -2432,6 +2432,42 @@ import MemberDescription from '@site/src/components/MemberDescription';
 <div class="graphql-code-line ">totalItems: <a href="/reference/graphql-api/shop/object-types#int">Int</a>!</div>
 <div class="graphql-code-line ">totalItems: <a href="/reference/graphql-api/shop/object-types#int">Int</a>!</div>
 
 
 
 
+<div class="graphql-code-line top-level">&#125;</div>
+</div>
+
+## PublicPaymentMethod
+
+<div class="graphql-code-block">
+<div class="graphql-code-line top-level">type <span class="graphql-code-identifier">PublicPaymentMethod</span> &#123;</div>
+<div class="graphql-code-line ">id: <a href="/reference/graphql-api/shop/object-types#id">ID</a>!</div>
+
+<div class="graphql-code-line ">code: <a href="/reference/graphql-api/shop/object-types#string">String</a>!</div>
+
+<div class="graphql-code-line ">name: <a href="/reference/graphql-api/shop/object-types#string">String</a>!</div>
+
+<div class="graphql-code-line ">description: <a href="/reference/graphql-api/shop/object-types#string">String</a></div>
+
+<div class="graphql-code-line ">translations: [<a href="/reference/graphql-api/shop/object-types#paymentmethodtranslation">PaymentMethodTranslation</a>!]!</div>
+
+
+<div class="graphql-code-line top-level">&#125;</div>
+</div>
+
+## PublicShippingMethod
+
+<div class="graphql-code-block">
+<div class="graphql-code-line top-level">type <span class="graphql-code-identifier">PublicShippingMethod</span> &#123;</div>
+<div class="graphql-code-line ">id: <a href="/reference/graphql-api/shop/object-types#id">ID</a>!</div>
+
+<div class="graphql-code-line ">code: <a href="/reference/graphql-api/shop/object-types#string">String</a>!</div>
+
+<div class="graphql-code-line ">name: <a href="/reference/graphql-api/shop/object-types#string">String</a>!</div>
+
+<div class="graphql-code-line ">description: <a href="/reference/graphql-api/shop/object-types#string">String</a></div>
+
+<div class="graphql-code-line ">translations: [<a href="/reference/graphql-api/shop/object-types#shippingmethodtranslation">ShippingMethodTranslation</a>!]!</div>
+
+
 <div class="graphql-code-line top-level">&#125;</div>
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
 </div>
 
 

+ 24 - 0
docs/docs/reference/graphql-api/shop/queries.md

@@ -47,6 +47,30 @@ import MemberDescription from '@site/src/components/MemberDescription';
 <div class="graphql-code-line ">activeOrder: <a href="/reference/graphql-api/shop/object-types#order">Order</a></div>
 <div class="graphql-code-line ">activeOrder: <a href="/reference/graphql-api/shop/object-types#order">Order</a></div>
 
 
 
 
+<div class="graphql-code-line top-level">&#125;</div>
+</div>
+
+## activePaymentMethods
+<div class="graphql-code-block">
+<div class="graphql-code-line top-level comment">"""</div>
+<div class="graphql-code-line top-level comment">Get active payment methods</div>
+<div class="graphql-code-line top-level comment">"""</div>
+<div class="graphql-code-line top-level">type <span class="graphql-code-identifier">Query</span> &#123;</div>
+<div class="graphql-code-line ">activePaymentMethods: [<a href="/reference/graphql-api/shop/object-types#publicpaymentmethod">PublicPaymentMethod</a>]!</div>
+
+
+<div class="graphql-code-line top-level">&#125;</div>
+</div>
+
+## activeShippingMethods
+<div class="graphql-code-block">
+<div class="graphql-code-line top-level comment">"""</div>
+<div class="graphql-code-line top-level comment">Get active shipping methods</div>
+<div class="graphql-code-line top-level comment">"""</div>
+<div class="graphql-code-line top-level">type <span class="graphql-code-identifier">Query</span> &#123;</div>
+<div class="graphql-code-line ">activeShippingMethods: [<a href="/reference/graphql-api/shop/object-types#publicshippingmethod">PublicShippingMethod</a>]!</div>
+
+
 <div class="graphql-code-line top-level">&#125;</div>
 <div class="graphql-code-line top-level">&#125;</div>
 </div>
 </div>
 
 

+ 1 - 1
docs/docs/reference/typescript-api/assets/asset-options.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## AssetOptions
 ## AssetOptions
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="648" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="650" packageName="@vendure/core" />
 
 
 The AssetOptions define how assets (images and other files) are named and stored, and how preview images are generated.
 The AssetOptions define how assets (images and other files) are named and stored, and how preview images are generated.
 
 

+ 1 - 1
docs/docs/reference/typescript-api/auth/auth-options.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## AuthOptions
 ## AuthOptions
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="333" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="335" packageName="@vendure/core" />
 
 
 The AuthOptions define how authentication and authorization is managed.
 The AuthOptions define how authentication and authorization is managed.
 
 

+ 1 - 1
docs/docs/reference/typescript-api/auth/cookie-options.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## CookieOptions
 ## CookieOptions
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="228" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="230" packageName="@vendure/core" />
 
 
 Options for the handling of the cookies used to track sessions (only applicable if
 Options for the handling of the cookies used to track sessions (only applicable if
 `authOptions.tokenMethod` is set to `'cookie'`). These options are passed directly
 `authOptions.tokenMethod` is set to `'cookie'`). These options are passed directly

+ 1 - 1
docs/docs/reference/typescript-api/auth/superadmin-credentials.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## SuperadminCredentials
 ## SuperadminCredentials
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="824" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="826" packageName="@vendure/core" />
 
 
 These credentials will be used to create the Superadmin user & administrator
 These credentials will be used to create the Superadmin user & administrator
 when Vendure first bootstraps.
 when Vendure first bootstraps.

+ 1 - 1
docs/docs/reference/typescript-api/common/permission.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## Permission
 ## Permission
 
 
-<GenerationInfo sourceFile="packages/common/src/generated-types.ts" sourceLine="4437" packageName="@vendure/common" />
+<GenerationInfo sourceFile="packages/common/src/generated-types.ts" sourceLine="4443" packageName="@vendure/common" />
 
 
 Permissions for administrators and customers. Used to control access to
 Permissions for administrators and customers. Used to control access to
 GraphQL resolvers via the <a href='/reference/typescript-api/request/allow-decorator#allow'>Allow</a> decorator.
 GraphQL resolvers via the <a href='/reference/typescript-api/request/allow-decorator#allow'>Allow</a> decorator.

+ 1 - 1
docs/docs/reference/typescript-api/configuration/api-options.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## ApiOptions
 ## ApiOptions
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="71" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="73" packageName="@vendure/core" />
 
 
 The ApiOptions define how the Vendure GraphQL APIs are exposed, as well as allowing the API layer
 The ApiOptions define how the Vendure GraphQL APIs are exposed, as well as allowing the API layer
 to be extended with middleware.
 to be extended with middleware.

+ 1 - 1
docs/docs/reference/typescript-api/configuration/entity-options.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## EntityOptions
 ## EntityOptions
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="974" packageName="@vendure/core" since="1.3.0" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="999" packageName="@vendure/core" since="1.3.0" />
 
 
 Options relating to the internal handling of entities.
 Options relating to the internal handling of entities.
 
 

+ 7 - 1
docs/docs/reference/typescript-api/configuration/runtime-vendure-config.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## RuntimeVendureConfig
 ## RuntimeVendureConfig
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="1230" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="1262" packageName="@vendure/core" />
 
 
 This interface represents the VendureConfig object available at run-time, i.e. the user-supplied
 This interface represents the VendureConfig object available at run-time, i.e. the user-supplied
 config values have been merged with the <a href='/reference/typescript-api/configuration/default-config#defaultconfig'>defaultConfig</a> values.
 config values have been merged with the <a href='/reference/typescript-api/configuration/default-config#defaultconfig'>defaultConfig</a> values.
@@ -26,6 +26,7 @@ interface RuntimeVendureConfig extends Required<VendureConfig> {
     entityOptions: Required<Omit<EntityOptions, 'entityIdStrategy'>> & EntityOptions;
     entityOptions: Required<Omit<EntityOptions, 'entityIdStrategy'>> & EntityOptions;
     importExportOptions: Required<ImportExportOptions>;
     importExportOptions: Required<ImportExportOptions>;
     jobQueueOptions: Required<JobQueueOptions>;
     jobQueueOptions: Required<JobQueueOptions>;
+    schedulerOptions: Required<SchedulerOptions>;
     orderOptions: Required<OrderOptions>;
     orderOptions: Required<OrderOptions>;
     promotionOptions: Required<PromotionOptions>;
     promotionOptions: Required<PromotionOptions>;
     shippingOptions: Required<ShippingOptions>;
     shippingOptions: Required<ShippingOptions>;
@@ -79,6 +80,11 @@ interface RuntimeVendureConfig extends Required<VendureConfig> {
 <MemberInfo kind="property" type={`Required&#60;<a href='/reference/typescript-api/job-queue/job-queue-options#jobqueueoptions'>JobQueueOptions</a>&#62;`}   />
 <MemberInfo kind="property" type={`Required&#60;<a href='/reference/typescript-api/job-queue/job-queue-options#jobqueueoptions'>JobQueueOptions</a>&#62;`}   />
 
 
 
 
+### schedulerOptions
+
+<MemberInfo kind="property" type={`Required&#60;<a href='/reference/typescript-api/scheduled-tasks/scheduler-options#scheduleroptions'>SchedulerOptions</a>&#62;`}   />
+
+
 ### orderOptions
 ### orderOptions
 
 
 <MemberInfo kind="property" type={`Required&#60;<a href='/reference/typescript-api/orders/order-options#orderoptions'>OrderOptions</a>&#62;`}   />
 <MemberInfo kind="property" type={`Required&#60;<a href='/reference/typescript-api/orders/order-options#orderoptions'>OrderOptions</a>&#62;`}   />

+ 1 - 1
docs/docs/reference/typescript-api/configuration/system-options.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## SystemOptions
 ## SystemOptions
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="1063" packageName="@vendure/core" since="1.6.0" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="1088" packageName="@vendure/core" since="1.6.0" />
 
 
 Options relating to system functions.
 Options relating to system functions.
 
 

+ 7 - 1
docs/docs/reference/typescript-api/configuration/vendure-config.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## VendureConfig
 ## VendureConfig
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="1100" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="1125" packageName="@vendure/core" />
 
 
 All possible configuration options are defined by the
 All possible configuration options are defined by the
 [`VendureConfig`](https://github.com/vendure-ecommerce/vendure/blob/master/packages/core/src/config/vendure-config.ts) interface.
 [`VendureConfig`](https://github.com/vendure-ecommerce/vendure/blob/master/packages/core/src/config/vendure-config.ts) interface.
@@ -37,6 +37,7 @@ interface VendureConfig {
     logger?: VendureLogger;
     logger?: VendureLogger;
     taxOptions?: TaxOptions;
     taxOptions?: TaxOptions;
     jobQueueOptions?: JobQueueOptions;
     jobQueueOptions?: JobQueueOptions;
+    schedulerOptions?: SchedulerOptions;
     systemOptions?: SystemOptions;
     systemOptions?: SystemOptions;
 }
 }
 ```
 ```
@@ -147,6 +148,11 @@ Configures how taxes are calculated on products.
 <MemberInfo kind="property" type={`<a href='/reference/typescript-api/job-queue/job-queue-options#jobqueueoptions'>JobQueueOptions</a>`}   />
 <MemberInfo kind="property" type={`<a href='/reference/typescript-api/job-queue/job-queue-options#jobqueueoptions'>JobQueueOptions</a>`}   />
 
 
 Configures how the job queue is persisted and processed.
 Configures how the job queue is persisted and processed.
+### schedulerOptions
+
+<MemberInfo kind="property" type={`<a href='/reference/typescript-api/scheduled-tasks/scheduler-options#scheduleroptions'>SchedulerOptions</a>`}  since="3.3.0"  />
+
+Configures the scheduler mechanism and tasks.
 ### systemOptions
 ### systemOptions
 
 
 <MemberInfo kind="property" type={`<a href='/reference/typescript-api/configuration/system-options#systemoptions'>SystemOptions</a>`}  since="1.6.0"  />
 <MemberInfo kind="property" type={`<a href='/reference/typescript-api/configuration/system-options#systemoptions'>SystemOptions</a>`}  since="1.6.0"  />

+ 1 - 1
docs/docs/reference/typescript-api/import-export/import-export-options.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## ImportExportOptions
 ## ImportExportOptions
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="909" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="911" packageName="@vendure/core" />
 
 
 Options related to importing & exporting data.
 Options related to importing & exporting data.
 
 

+ 1 - 1
docs/docs/reference/typescript-api/job-queue/job-queue-options.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## JobQueueOptions
 ## JobQueueOptions
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="933" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="935" packageName="@vendure/core" />
 
 
 Options related to the built-in job queue.
 Options related to the built-in job queue.
 
 

+ 1 - 1
docs/docs/reference/typescript-api/orders/order-options.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## OrderOptions
 ## OrderOptions
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="494" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="496" packageName="@vendure/core" />
 
 
 
 
 
 

+ 1 - 1
docs/docs/reference/typescript-api/payment/payment-options.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## PaymentOptions
 ## PaymentOptions
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="846" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="848" packageName="@vendure/core" />
 
 
 Defines payment-related options in the <a href='/reference/typescript-api/configuration/vendure-config#vendureconfig'>VendureConfig</a>.
 Defines payment-related options in the <a href='/reference/typescript-api/configuration/vendure-config#vendureconfig'>VendureConfig</a>.
 
 

+ 1 - 1
docs/docs/reference/typescript-api/products-stock/catalog-options.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## CatalogOptions
 ## CatalogOptions
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="695" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="697" packageName="@vendure/core" />
 
 
 Options related to products and collections.
 Options related to products and collections.
 
 

+ 1 - 1
docs/docs/reference/typescript-api/promotions/promotion-options.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## PromotionOptions
 ## PromotionOptions
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="757" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="759" packageName="@vendure/core" />
 
 
 
 
 
 

+ 44 - 0
docs/docs/reference/typescript-api/scheduled-tasks/clean-sessions-task.md

@@ -0,0 +1,44 @@
+---
+title: "CleanSessionsTask"
+isDefaultIndex: false
+generated: true
+---
+<!-- This file was generated from the Vendure source. Do not modify. Instead, re-run the "docs:build" script -->
+import MemberInfo from '@site/src/components/MemberInfo';
+import GenerationInfo from '@site/src/components/GenerationInfo';
+import MemberDescription from '@site/src/components/MemberDescription';
+
+
+## cleanSessionsTask
+
+<GenerationInfo sourceFile="packages/core/src/scheduler/tasks/clean-sessions-task.ts" sourceLine="37" packageName="@vendure/core" since="3.3.0" />
+
+A scheduled task that cleans expired & inactive sessions from the database.
+
+*Example*
+
+```ts
+import { cleanSessionsTask, VendureConfig } from '@vendure/core';
+
+export const config: VendureConfig = {
+  // ...
+  schedulerOptions: {
+    tasks: [
+      // Use the task as is
+      cleanSessionsTask,
+      // or configure the task
+      cleanSessionsTask.configure({
+        // Run the task every day at 3:00am
+        // The default schedule is every day at 00:00am
+        schedule: cron => cron.everyDayAt(3, 0),
+        params: {
+          // How many sessions to process in each batch
+          // Default: 10_000
+          batchSize: 5_000,
+        },
+      }),
+    ],
+  },
+};
+```
+

+ 83 - 0
docs/docs/reference/typescript-api/scheduled-tasks/default-scheduler-plugin.md

@@ -0,0 +1,83 @@
+---
+title: "DefaultSchedulerPlugin"
+isDefaultIndex: false
+generated: true
+---
+<!-- This file was generated from the Vendure source. Do not modify. Instead, re-run the "docs:build" script -->
+import MemberInfo from '@site/src/components/MemberInfo';
+import GenerationInfo from '@site/src/components/GenerationInfo';
+import MemberDescription from '@site/src/components/MemberDescription';
+
+
+## DefaultSchedulerPlugin
+
+<GenerationInfo sourceFile="packages/core/src/plugin/default-scheduler-plugin/default-scheduler.plugin.ts" sourceLine="35" packageName="@vendure/core" since="3.3.0" />
+
+This plugin configures a default scheduling strategy that executes scheduled
+tasks using the database to ensure that each task is executed exactly once
+at the scheduled time, even if there are multiple instances of the worker
+running.
+
+*Example*
+
+```ts
+import { DefaultSchedulerPlugin, VendureConfig } from '@vendure/core';
+
+export const config: VendureConfig = {
+  plugins: [
+    DefaultSchedulerPlugin.init({
+      // The default is 60s, but you can override it here
+      defaultTimeout: '10s',
+    }),
+  ],
+};
+```
+
+```ts title="Signature"
+class DefaultSchedulerPlugin {
+    static options: DefaultSchedulerPluginOptions = {
+        defaultTimeout: DEFAULT_TIMEOUT,
+    };
+    init(config: DefaultSchedulerPluginOptions) => ;
+}
+```
+
+<div className="members-wrapper">
+
+### options
+
+<MemberInfo kind="property" type={`<a href='/reference/typescript-api/scheduled-tasks/default-scheduler-plugin#defaultschedulerpluginoptions'>DefaultSchedulerPluginOptions</a>`}   />
+
+
+### init
+
+<MemberInfo kind="method" type={`(config: <a href='/reference/typescript-api/scheduled-tasks/default-scheduler-plugin#defaultschedulerpluginoptions'>DefaultSchedulerPluginOptions</a>) => `}   />
+
+
+
+
+</div>
+
+
+## DefaultSchedulerPluginOptions
+
+<GenerationInfo sourceFile="packages/core/src/plugin/default-scheduler-plugin/types.ts" sourceLine="9" packageName="@vendure/core" since="3.3.0" />
+
+The options for the <a href='/reference/typescript-api/scheduled-tasks/default-scheduler-plugin#defaultschedulerplugin'>DefaultSchedulerPlugin</a>.
+
+```ts title="Signature"
+interface DefaultSchedulerPluginOptions {
+    defaultTimeout?: string | number;
+}
+```
+
+<div className="members-wrapper">
+
+### defaultTimeout
+
+<MemberInfo kind="property" type={`string | number`} default={`60_000ms`}   />
+
+The default timeout for scheduled tasks.
+
+
+</div>

+ 68 - 0
docs/docs/reference/typescript-api/scheduled-tasks/default-scheduler-strategy.md

@@ -0,0 +1,68 @@
+---
+title: "DefaultSchedulerStrategy"
+isDefaultIndex: false
+generated: true
+---
+<!-- This file was generated from the Vendure source. Do not modify. Instead, re-run the "docs:build" script -->
+import MemberInfo from '@site/src/components/MemberInfo';
+import GenerationInfo from '@site/src/components/GenerationInfo';
+import MemberDescription from '@site/src/components/MemberDescription';
+
+
+## DefaultSchedulerStrategy
+
+<GenerationInfo sourceFile="packages/core/src/plugin/default-scheduler-plugin/default-scheduler-strategy.ts" sourceLine="25" packageName="@vendure/core" since="3.3.0" />
+
+The default <a href='/reference/typescript-api/scheduled-tasks/scheduler-strategy#schedulerstrategy'>SchedulerStrategy</a> implementation that uses the database to
+execute scheduled tasks. This strategy is configured when you use the
+<a href='/reference/typescript-api/scheduled-tasks/default-scheduler-plugin#defaultschedulerplugin'>DefaultSchedulerPlugin</a>.
+
+```ts title="Signature"
+class DefaultSchedulerStrategy implements SchedulerStrategy {
+    init(injector: Injector) => ;
+    destroy() => ;
+    executeTask(task: ScheduledTask) => ;
+    getTasks() => Promise<TaskReport[]>;
+    getTask(id: string) => Promise<TaskReport | undefined>;
+    updateTask(input: UpdateScheduledTaskInput) => Promise<TaskReport>;
+}
+```
+* Implements: <code><a href='/reference/typescript-api/scheduled-tasks/scheduler-strategy#schedulerstrategy'>SchedulerStrategy</a></code>
+
+
+
+<div className="members-wrapper">
+
+### init
+
+<MemberInfo kind="method" type={`(injector: <a href='/reference/typescript-api/common/injector#injector'>Injector</a>) => `}   />
+
+
+### destroy
+
+<MemberInfo kind="method" type={`() => `}   />
+
+
+### executeTask
+
+<MemberInfo kind="method" type={`(task: <a href='/reference/typescript-api/scheduled-tasks/scheduled-task#scheduledtask'>ScheduledTask</a>) => `}   />
+
+
+### getTasks
+
+<MemberInfo kind="method" type={`() => Promise&#60;<a href='/reference/typescript-api/scheduled-tasks/scheduler-strategy#taskreport'>TaskReport</a>[]&#62;`}   />
+
+
+### getTask
+
+<MemberInfo kind="method" type={`(id: string) => Promise&#60;<a href='/reference/typescript-api/scheduled-tasks/scheduler-strategy#taskreport'>TaskReport</a> | undefined&#62;`}   />
+
+
+### updateTask
+
+<MemberInfo kind="method" type={`(input: UpdateScheduledTaskInput) => Promise&#60;<a href='/reference/typescript-api/scheduled-tasks/scheduler-strategy#taskreport'>TaskReport</a>&#62;`}   />
+
+
+
+
+</div>

+ 14 - 0
docs/docs/reference/typescript-api/scheduled-tasks/index.md

@@ -0,0 +1,14 @@
+---
+title: "Scheduled Tasks"
+isDefaultIndex: true
+generated: true
+---
+<!-- This file was generated from the Vendure source. Do not modify. Instead, re-run the "docs:build" script -->
+import MemberInfo from '@site/src/components/MemberInfo';
+import GenerationInfo from '@site/src/components/GenerationInfo';
+import MemberDescription from '@site/src/components/MemberDescription';
+
+
+import DocCardList from '@theme/DocCardList';
+
+<DocCardList />

+ 164 - 0
docs/docs/reference/typescript-api/scheduled-tasks/scheduled-task.md

@@ -0,0 +1,164 @@
+---
+title: "ScheduledTask"
+isDefaultIndex: false
+generated: true
+---
+<!-- This file was generated from the Vendure source. Do not modify. Instead, re-run the "docs:build" script -->
+import MemberInfo from '@site/src/components/MemberInfo';
+import GenerationInfo from '@site/src/components/GenerationInfo';
+import MemberDescription from '@site/src/components/MemberDescription';
+
+
+## ScheduledTask
+
+<GenerationInfo sourceFile="packages/core/src/scheduler/scheduled-task.ts" sourceLine="90" packageName="@vendure/core" since="3.3.0" />
+
+Use this class to define a scheduled task that will be executed at a given cron schedule.
+
+*Example*
+
+```ts
+import { ScheduledTask } from '@vendure/core';
+
+const task = new ScheduledTask({
+    id: 'test-job',
+    schedule: cron => cron.every(2).minutes(),
+    execute: async (injector, params) => {
+        // some logic here
+    },
+});
+```
+
+```ts title="Signature"
+class ScheduledTask<C extends Record<string, any> = Record<string, any>> {
+    constructor(config: ScheduledTaskConfig<C>)
+    id: void
+    options: void
+    execute(injector: Injector) => ;
+    configure(additionalConfig: Partial<Pick<ScheduledTaskConfig<C>, 'schedule' | 'timeout' | 'params'>>) => ;
+}
+```
+
+<div className="members-wrapper">
+
+### constructor
+
+<MemberInfo kind="method" type={`(config: <a href='/reference/typescript-api/scheduled-tasks/scheduled-task#scheduledtaskconfig'>ScheduledTaskConfig</a>&#60;C&#62;) => ScheduledTask`}   />
+
+
+### id
+
+<MemberInfo kind="property" type={``}   />
+
+
+### options
+
+<MemberInfo kind="property" type={``}   />
+
+
+### execute
+
+<MemberInfo kind="method" type={`(injector: <a href='/reference/typescript-api/common/injector#injector'>Injector</a>) => `}   />
+
+
+### configure
+
+<MemberInfo kind="method" type={`(additionalConfig: Partial&#60;Pick&#60;<a href='/reference/typescript-api/scheduled-tasks/scheduled-task#scheduledtaskconfig'>ScheduledTaskConfig</a>&#60;C&#62;, 'schedule' | 'timeout' | 'params'&#62;&#62;) => `}   />
+
+This method allows you to further configure existing scheduled tasks. For example, you may
+wish to change the schedule or timeout of a task, without having to define a new task.
+
+*Example*
+
+```ts
+import { ScheduledTask } from '@vendure/core';
+
+const task = new ScheduledTask({
+    id: 'test-job',
+    schedule: cron => cron.every(2).minutes(),
+    execute: async (injector, params) => {
+        // some logic here
+    },
+});
+
+// later, you can configure the task
+task.configure({ schedule: cron => cron.every(5).minutes() });
+```
+
+
+</div>
+
+
+## ScheduledTaskConfig
+
+<GenerationInfo sourceFile="packages/core/src/scheduler/scheduled-task.ts" sourceLine="12" packageName="@vendure/core" since="3.3.0" />
+
+The configuration for a scheduled task.
+
+```ts title="Signature"
+interface ScheduledTaskConfig<C extends Record<string, any> = Record<string, any>> {
+    id: string;
+    description?: string;
+    params?: C;
+    schedule: string | ((cronTime: typeof CronTime) => string);
+    timeout?: number | string;
+    preventOverlap?: boolean;
+    execute(injector: Injector, config: C): Promise<any>;
+}
+```
+
+<div className="members-wrapper">
+
+### id
+
+<MemberInfo kind="property" type={`string`}   />
+
+The unique identifier for the scheduled task.
+### description
+
+<MemberInfo kind="property" type={`string`}   />
+
+The description for the scheduled task.
+### params
+
+<MemberInfo kind="property" type={`C`}   />
+
+Optional parameters that will be passed to the `execute` function.
+### schedule
+
+<MemberInfo kind="property" type={`string | ((cronTime: typeof CronTime) =&#62; string)`}   />
+
+The cron schedule for the scheduled task. This can be a standard cron expression or
+a function that returns a [cron-time-generator](https://www.npmjs.com/package/cron-time-generator)
+expression.
+
+*Example*
+
+```ts
+// Standard cron expression
+{ schedule: '0 0-23/5 * * *', } // every 5 hours
+{ schedule: '0 22 * * *', } // every day at 10:00 PM
+
+// Cron-time-generator expression
+{ schedule: cronTime => cronTime.every(2).minutes(), }
+{ schedule: cronTime => cronTime.every(5).hours(), }
+```
+### timeout
+
+<MemberInfo kind="property" type={`number | string`} default={`60_000ms`}   />
+
+The timeout for the scheduled task. If the task takes longer than the timeout, the task
+will be considered to have failed with a timeout error.
+### preventOverlap
+
+<MemberInfo kind="property" type={`boolean`} default={`true`}   />
+
+Whether the scheduled task should be prevented from running if it is already running.
+### execute
+
+<MemberInfo kind="method" type={`(injector: <a href='/reference/typescript-api/common/injector#injector'>Injector</a>, config: C) => Promise&#60;any&#62;`}   />
+
+The function that will be executed when the scheduled task is run.
+
+
+</div>

+ 41 - 0
docs/docs/reference/typescript-api/scheduled-tasks/scheduler-options.md

@@ -0,0 +1,41 @@
+---
+title: "SchedulerOptions"
+isDefaultIndex: false
+generated: true
+---
+<!-- This file was generated from the Vendure source. Do not modify. Instead, re-run the "docs:build" script -->
+import MemberInfo from '@site/src/components/MemberInfo';
+import GenerationInfo from '@site/src/components/GenerationInfo';
+import MemberDescription from '@site/src/components/MemberDescription';
+
+
+## SchedulerOptions
+
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="974" packageName="@vendure/core" since="3.3.0" />
+
+Options related to scheduled tasks..
+
+```ts title="Signature"
+interface SchedulerOptions {
+    schedulerStrategy?: SchedulerStrategy;
+    tasks?: ScheduledTask[];
+}
+```
+
+<div className="members-wrapper">
+
+### schedulerStrategy
+
+<MemberInfo kind="property" type={`<a href='/reference/typescript-api/scheduled-tasks/scheduler-strategy#schedulerstrategy'>SchedulerStrategy</a>`}   />
+
+The strategy used to execute scheduled tasks. If you are using the
+<a href='/reference/typescript-api/scheduled-tasks/default-scheduler-plugin#defaultschedulerplugin'>DefaultSchedulerPlugin</a> (which is recommended) then this will be set to the
+<a href='/reference/typescript-api/scheduled-tasks/default-scheduler-strategy#defaultschedulerstrategy'>DefaultSchedulerStrategy</a>.
+### tasks
+
+<MemberInfo kind="property" type={`<a href='/reference/typescript-api/scheduled-tasks/scheduled-task#scheduledtask'>ScheduledTask</a>[]`}   />
+
+The tasks to be executed.
+
+
+</div>

+ 54 - 0
docs/docs/reference/typescript-api/scheduled-tasks/scheduler-service.md

@@ -0,0 +1,54 @@
+---
+title: "SchedulerService"
+isDefaultIndex: false
+generated: true
+---
+<!-- This file was generated from the Vendure source. Do not modify. Instead, re-run the "docs:build" script -->
+import MemberInfo from '@site/src/components/MemberInfo';
+import GenerationInfo from '@site/src/components/GenerationInfo';
+import MemberDescription from '@site/src/components/MemberDescription';
+
+
+## SchedulerService
+
+<GenerationInfo sourceFile="packages/core/src/scheduler/scheduler.service.ts" sourceLine="33" packageName="@vendure/core" since="3.3.0" />
+
+The service that is responsible for setting up and querying the scheduled tasks.
+
+```ts title="Signature"
+class SchedulerService implements OnApplicationBootstrap {
+    constructor(configService: ConfigService)
+    onApplicationBootstrap() => ;
+    getTaskList() => Promise<TaskInfo[]>;
+    updateTask(input: UpdateScheduledTaskInput) => Promise<TaskInfo>;
+}
+```
+* Implements: <code>OnApplicationBootstrap</code>
+
+
+
+<div className="members-wrapper">
+
+### constructor
+
+<MemberInfo kind="method" type={`(configService: ConfigService) => SchedulerService`}   />
+
+
+### onApplicationBootstrap
+
+<MemberInfo kind="method" type={`() => `}   />
+
+
+### getTaskList
+
+<MemberInfo kind="method" type={`() => Promise&#60;TaskInfo[]&#62;`}   />
+
+Returns a list of all the scheduled tasks and their current status.
+### updateTask
+
+<MemberInfo kind="method" type={`(input: UpdateScheduledTaskInput) => Promise&#60;TaskInfo&#62;`}   />
+
+
+
+
+</div>

+ 119 - 0
docs/docs/reference/typescript-api/scheduled-tasks/scheduler-strategy.md

@@ -0,0 +1,119 @@
+---
+title: "SchedulerStrategy"
+isDefaultIndex: false
+generated: true
+---
+<!-- This file was generated from the Vendure source. Do not modify. Instead, re-run the "docs:build" script -->
+import MemberInfo from '@site/src/components/MemberInfo';
+import GenerationInfo from '@site/src/components/GenerationInfo';
+import MemberDescription from '@site/src/components/MemberDescription';
+
+
+## SchedulerStrategy
+
+<GenerationInfo sourceFile="packages/core/src/scheduler/scheduler-strategy.ts" sourceLine="42" packageName="@vendure/core" since="3.3.0" />
+
+This strategy is used to define the mechanism by which scheduled tasks are executed
+and how they are reported on. The main purpose of this strategy is to ensure
+that a given task is executed exactly once at the scheduled time, even if there
+are multiple instances of the worker running.
+
+To do this, the strategy must use some form of shared storage and a method of
+locking so that only a single worker is allowed to execute the task.
+
+By default, the <a href='/reference/typescript-api/scheduled-tasks/default-scheduler-strategy#defaultschedulerstrategy'>DefaultSchedulerStrategy</a> will use the database to enable
+this functionality.
+
+```ts title="Signature"
+interface SchedulerStrategy extends InjectableStrategy {
+    executeTask(task: ScheduledTask): (job: Cron) => Promise<any> | any;
+    getTasks(): Promise<TaskReport[]>;
+    getTask(id: string): Promise<TaskReport | undefined>;
+    updateTask(input: UpdateScheduledTaskInput): Promise<TaskReport>;
+}
+```
+* Extends: <code><a href='/reference/typescript-api/common/injectable-strategy#injectablestrategy'>InjectableStrategy</a></code>
+
+
+
+<div className="members-wrapper">
+
+### executeTask
+
+<MemberInfo kind="method" type={`(task: <a href='/reference/typescript-api/scheduled-tasks/scheduled-task#scheduledtask'>ScheduledTask</a>) => (job: Cron) =&#62; Promise&#60;any&#62; | any`}   />
+
+Execute a scheduled task. This method must also take care of
+ensuring that the task is executed exactly once at the scheduled time,
+even if there are multiple instances of the worker running.
+
+For instance, in the <a href='/reference/typescript-api/scheduled-tasks/default-scheduler-strategy#defaultschedulerstrategy'>DefaultSchedulerStrategy</a> we make use of a
+dedicated database table and a locking mechansim. If you implement a custom
+SchedulerStrategy, you must use some other form of shared locking mechanism
+that could make use of something like Redis etc. to ensure that the task
+is executed exactly once at the scheduled time.
+### getTasks
+
+<MemberInfo kind="method" type={`() => Promise&#60;<a href='/reference/typescript-api/scheduled-tasks/scheduler-strategy#taskreport'>TaskReport</a>[]&#62;`}   />
+
+Get all scheduled tasks.
+### getTask
+
+<MemberInfo kind="method" type={`(id: string) => Promise&#60;<a href='/reference/typescript-api/scheduled-tasks/scheduler-strategy#taskreport'>TaskReport</a> | undefined&#62;`}   />
+
+Get a single scheduled task by its id.
+### updateTask
+
+<MemberInfo kind="method" type={`(input: UpdateScheduledTaskInput) => Promise&#60;<a href='/reference/typescript-api/scheduled-tasks/scheduler-strategy#taskreport'>TaskReport</a>&#62;`}   />
+
+Update a scheduled task.
+
+
+</div>
+
+
+## TaskReport
+
+<GenerationInfo sourceFile="packages/core/src/scheduler/scheduler-strategy.ts" sourceLine="16" packageName="@vendure/core" since="3.3.0" />
+
+A report on the status of a scheduled task.
+
+```ts title="Signature"
+interface TaskReport {
+    id: string;
+    lastExecutedAt: Date | null;
+    isRunning: boolean;
+    lastResult: any;
+    enabled: boolean;
+}
+```
+
+<div className="members-wrapper">
+
+### id
+
+<MemberInfo kind="property" type={`string`}   />
+
+
+### lastExecutedAt
+
+<MemberInfo kind="property" type={`Date | null`}   />
+
+
+### isRunning
+
+<MemberInfo kind="property" type={`boolean`}   />
+
+
+### lastResult
+
+<MemberInfo kind="property" type={`any`}   />
+
+
+### enabled
+
+<MemberInfo kind="property" type={`boolean`}   />
+
+
+
+
+</div>

+ 23 - 5
docs/docs/reference/typescript-api/services/session-service.md

@@ -11,13 +11,14 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## SessionService
 ## SessionService
 
 
-<GenerationInfo sourceFile="packages/core/src/service/services/session.service.ts" sourceLine="28" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/service/services/session.service.ts" sourceLine="31" packageName="@vendure/core" />
 
 
 Contains methods relating to <a href='/reference/typescript-api/entities/session#session'>Session</a> entities.
 Contains methods relating to <a href='/reference/typescript-api/entities/session#session'>Session</a> entities.
 
 
 ```ts title="Signature"
 ```ts title="Signature"
-class SessionService implements EntitySubscriberInterface {
-    constructor(connection: TransactionalConnection, configService: ConfigService, orderService: OrderService)
+class SessionService implements EntitySubscriberInterface, OnApplicationBootstrap {
+    constructor(connection: TransactionalConnection, configService: ConfigService, orderService: OrderService, jobQueueService: JobQueueService, requestContextService: RequestContextService)
+    onApplicationBootstrap() => ;
     createNewAuthenticatedSession(ctx: RequestContext, user: User, authenticationStrategyName: string) => Promise<AuthenticatedSession>;
     createNewAuthenticatedSession(ctx: RequestContext, user: User, authenticationStrategyName: string) => Promise<AuthenticatedSession>;
     createAnonymousSession() => Promise<CachedSession>;
     createAnonymousSession() => Promise<CachedSession>;
     getSessionFromToken(sessionToken: string) => Promise<CachedSession | undefined>;
     getSessionFromToken(sessionToken: string) => Promise<CachedSession | undefined>;
@@ -27,9 +28,11 @@ class SessionService implements EntitySubscriberInterface {
     setActiveChannel(serializedSession: CachedSession, channel: Channel) => Promise<CachedSession>;
     setActiveChannel(serializedSession: CachedSession, channel: Channel) => Promise<CachedSession>;
     deleteSessionsByUser(ctx: RequestContext, user: User) => Promise<void>;
     deleteSessionsByUser(ctx: RequestContext, user: User) => Promise<void>;
     deleteSessionsByActiveOrderId(ctx: RequestContext, activeOrderId: ID) => Promise<void>;
     deleteSessionsByActiveOrderId(ctx: RequestContext, activeOrderId: ID) => Promise<void>;
+    triggerCleanSessionsJob(batchSize: number) => ;
+    cleanExpiredSessions(ctx: RequestContext, batchSize: number) => ;
 }
 }
 ```
 ```
-* Implements: <code>EntitySubscriberInterface</code>
+* Implements: <code>EntitySubscriberInterface</code>, <code>OnApplicationBootstrap</code>
 
 
 
 
 
 
@@ -37,7 +40,12 @@ class SessionService implements EntitySubscriberInterface {
 
 
 ### constructor
 ### constructor
 
 
-<MemberInfo kind="method" type={`(connection: <a href='/reference/typescript-api/data-access/transactional-connection#transactionalconnection'>TransactionalConnection</a>, configService: ConfigService, orderService: <a href='/reference/typescript-api/services/order-service#orderservice'>OrderService</a>) => SessionService`}   />
+<MemberInfo kind="method" type={`(connection: <a href='/reference/typescript-api/data-access/transactional-connection#transactionalconnection'>TransactionalConnection</a>, configService: ConfigService, orderService: <a href='/reference/typescript-api/services/order-service#orderservice'>OrderService</a>, jobQueueService: <a href='/reference/typescript-api/job-queue/job-queue-service#jobqueueservice'>JobQueueService</a>, requestContextService: <a href='/reference/typescript-api/request/request-context-service#requestcontextservice'>RequestContextService</a>) => SessionService`}   />
+
+
+### onApplicationBootstrap
+
+<MemberInfo kind="method" type={`() => `}   />
 
 
 
 
 ### createNewAuthenticatedSession
 ### createNewAuthenticatedSession
@@ -86,6 +94,16 @@ Deletes all existing sessions for the given user.
 <MemberInfo kind="method" type={`(ctx: <a href='/reference/typescript-api/request/request-context#requestcontext'>RequestContext</a>, activeOrderId: <a href='/reference/typescript-api/common/id#id'>ID</a>) => Promise&#60;void&#62;`}   />
 <MemberInfo kind="method" type={`(ctx: <a href='/reference/typescript-api/request/request-context#requestcontext'>RequestContext</a>, activeOrderId: <a href='/reference/typescript-api/common/id#id'>ID</a>) => Promise&#60;void&#62;`}   />
 
 
 Deletes all existing sessions with the given activeOrder.
 Deletes all existing sessions with the given activeOrder.
+### triggerCleanSessionsJob
+
+<MemberInfo kind="method" type={`(batchSize: number) => `}   />
+
+Triggers the clean sessions job.
+### cleanExpiredSessions
+
+<MemberInfo kind="method" type={`(ctx: <a href='/reference/typescript-api/request/request-context#requestcontext'>RequestContext</a>, batchSize: number) => `}   />
+
+Cleans expired sessions from the database & the session cache.
 
 
 
 
 </div>
 </div>

+ 1 - 1
docs/docs/reference/typescript-api/shipping/shipping-options.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## ShippingOptions
 ## ShippingOptions
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="773" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="775" packageName="@vendure/core" />
 
 
 
 
 
 

+ 1 - 1
docs/docs/reference/typescript-api/tax/tax-options.md

@@ -11,7 +11,7 @@ import MemberDescription from '@site/src/components/MemberDescription';
 
 
 ## TaxOptions
 ## TaxOptions
 
 
-<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="886" packageName="@vendure/core" />
+<GenerationInfo sourceFile="packages/core/src/config/vendure-config.ts" sourceLine="888" packageName="@vendure/core" />
 
 
 
 
 
 

+ 4 - 2
packages/core/src/plugin/default-scheduler-plugin/default-scheduler.plugin.ts

@@ -29,6 +29,8 @@ import { DefaultSchedulerPluginOptions } from './types';
  *
  *
  * @since 3.3.0
  * @since 3.3.0
  * @docsCategory scheduled-tasks
  * @docsCategory scheduled-tasks
+ * @docsPage DefaultSchedulerPlugin
+ * @docsWeight 0
  */
  */
 @VendurePlugin({
 @VendurePlugin({
     imports: [PluginCommonModule],
     imports: [PluginCommonModule],
@@ -50,8 +52,8 @@ export class DefaultSchedulerPlugin {
         defaultTimeout: DEFAULT_TIMEOUT,
         defaultTimeout: DEFAULT_TIMEOUT,
     };
     };
 
 
-    static init(config: DefaultSchedulerPluginOptions) {
-        this.options = { ...this.options, ...config };
+    static init(config?: DefaultSchedulerPluginOptions) {
+        this.options = { ...this.options, ...(config || {}) };
         return this;
         return this;
     }
     }
 }
 }

+ 1 - 0
packages/core/src/plugin/default-scheduler-plugin/types.ts

@@ -4,6 +4,7 @@
  *
  *
  * @since 3.3.0
  * @since 3.3.0
  * @docsCategory scheduled-tasks
  * @docsCategory scheduled-tasks
+ * @docsPage DefaultSchedulerPlugin
  */
  */
 export interface DefaultSchedulerPluginOptions {
 export interface DefaultSchedulerPluginOptions {
     /**
     /**

+ 18 - 1
packages/core/src/scheduler/scheduled-task.ts

@@ -6,6 +6,8 @@ import { Injector } from '../common/index';
  * The configuration for a scheduled task.
  * The configuration for a scheduled task.
  *
  *
  * @since 3.3.0
  * @since 3.3.0
+ * @docsCategory scheduled-tasks
+ * @docsPage ScheduledTask
  */
  */
 export interface ScheduledTaskConfig<C extends Record<string, any> = Record<string, any>> {
 export interface ScheduledTaskConfig<C extends Record<string, any> = Record<string, any>> {
     /**
     /**
@@ -65,10 +67,25 @@ export interface ScheduledTaskConfig<C extends Record<string, any> = Record<stri
 
 
 /**
 /**
  * @description
  * @description
- * A scheduled task that will be executed at a given cron schedule.
+ * Use this class to define a scheduled task that will be executed at a given cron schedule.
+ *
+ * @example
+ * ```ts
+ * import { ScheduledTask } from '\@vendure/core';
+ *
+ * const task = new ScheduledTask({
+ *     id: 'test-job',
+ *     schedule: cron => cron.every(2).minutes(),
+ *     execute: async (injector, params) => {
+ *         // some logic here
+ *     },
+ * });
+ * ```
  *
  *
  * @since 3.3.0
  * @since 3.3.0
  * @docsCategory scheduled-tasks
  * @docsCategory scheduled-tasks
+ * @docsPage ScheduledTask
+ * @docsWeight 0
  */
  */
 export class ScheduledTask<C extends Record<string, any> = Record<string, any>> {
 export class ScheduledTask<C extends Record<string, any> = Record<string, any>> {
     constructor(private readonly config: ScheduledTaskConfig<C>) {}
     constructor(private readonly config: ScheduledTaskConfig<C>) {}

+ 34 - 0
packages/core/src/scheduler/scheduler-strategy.ts

@@ -5,6 +5,14 @@ import { InjectableStrategy } from '../common';
 
 
 import { ScheduledTask } from './scheduled-task';
 import { ScheduledTask } from './scheduled-task';
 
 
+/**
+ * @description
+ * A report on the status of a scheduled task.
+ *
+ * @since 3.3.0
+ * @docsCategory scheduled-tasks
+ * @docsPage SchedulerStrategy
+ */
 export interface TaskReport {
 export interface TaskReport {
     id: string;
     id: string;
     lastExecutedAt: Date | null;
     lastExecutedAt: Date | null;
@@ -28,10 +36,36 @@ export interface TaskReport {
  *
  *
  * @since 3.3.0
  * @since 3.3.0
  * @docsCategory scheduled-tasks
  * @docsCategory scheduled-tasks
+ * @docsPage SchedulerStrategy
+ * @docsWeight 0
  */
  */
 export interface SchedulerStrategy extends InjectableStrategy {
 export interface SchedulerStrategy extends InjectableStrategy {
+    /**
+     * @description
+     * Execute a scheduled task. This method must also take care of
+     * ensuring that the task is executed exactly once at the scheduled time,
+     * even if there are multiple instances of the worker running.
+     *
+     * For instance, in the {@link DefaultSchedulerStrategy} we make use of a
+     * dedicated database table and a locking mechansim. If you implement a custom
+     * SchedulerStrategy, you must use some other form of shared locking mechanism
+     * that could make use of something like Redis etc. to ensure that the task
+     * is executed exactly once at the scheduled time.
+     */
     executeTask(task: ScheduledTask): (job: Cron) => Promise<any> | any;
     executeTask(task: ScheduledTask): (job: Cron) => Promise<any> | any;
+    /**
+     * @description
+     * Get all scheduled tasks.
+     */
     getTasks(): Promise<TaskReport[]>;
     getTasks(): Promise<TaskReport[]>;
+    /**
+     * @description
+     * Get a single scheduled task by its id.
+     */
     getTask(id: string): Promise<TaskReport | undefined>;
     getTask(id: string): Promise<TaskReport | undefined>;
+    /**
+     * @description
+     * Update a scheduled task.
+     */
     updateTask(input: UpdateScheduledTaskInput): Promise<TaskReport>;
     updateTask(input: UpdateScheduledTaskInput): Promise<TaskReport>;
 }
 }

+ 26 - 0
packages/core/src/scheduler/tasks/clean-sessions-task.ts

@@ -5,6 +5,32 @@ import { ScheduledTask } from '../scheduled-task';
  * @description
  * @description
  * A scheduled task that cleans expired & inactive sessions from the database.
  * A scheduled task that cleans expired & inactive sessions from the database.
  *
  *
+ * @example
+ * ```ts
+ * import { cleanSessionsTask, VendureConfig } from '\@vendure/core';
+ *
+ * export const config: VendureConfig = {
+ *   // ...
+ *   schedulerOptions: {
+ *     tasks: [
+ *       // Use the task as is
+ *       cleanSessionsTask,
+ *       // or configure the task
+ *       cleanSessionsTask.configure({
+ *         // Run the task every day at 3:00am
+ *         // The default schedule is every day at 00:00am
+ *         schedule: cron => cron.everyDayAt(3, 0),
+ *         params: {
+ *           // How many sessions to process in each batch
+ *           // Default: 10_000
+ *           batchSize: 5_000,
+ *         },
+ *       }),
+ *     ],
+ *   },
+ * };
+ * ```
+ *
  * @since 3.3.0
  * @since 3.3.0
  * @docsCategory scheduled-tasks
  * @docsCategory scheduled-tasks
  */
  */