From d6fa912b2222649d522fb02a7a34332b076e20a4 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Tue, 26 Nov 2024 16:19:53 +0200 Subject: [PATCH] docs: revise scheduled jobs (#10291) --- .../app/learn/basics/scheduled-jobs/page.mdx | 120 ++++++++---------- www/apps/book/generated/edit-dates.mjs | 2 +- 2 files changed, 55 insertions(+), 67 deletions(-) diff --git a/www/apps/book/app/learn/basics/scheduled-jobs/page.mdx b/www/apps/book/app/learn/basics/scheduled-jobs/page.mdx index f589ae46c6..e7d254ea5e 100644 --- a/www/apps/book/app/learn/basics/scheduled-jobs/page.mdx +++ b/www/apps/book/app/learn/basics/scheduled-jobs/page.mdx @@ -8,43 +8,63 @@ In this chapter, you’ll learn about scheduled jobs and how to use them. ## What is a Scheduled Job? -A scheduled job is a function executed at a specified interval of time in the background of your Medusa application. It’s like a cron job that runs during the application's runtime. +When building your commerce application, you may need to automate tasks and run them repeatedly at a specific schedule. For example, you need to automatically sync products to a third-party service once a day. -For example, you can synchronize your inventory with an Enterprise Resource Planning (ERP) system once a day using a scheduled job. +In other commerce platforms, this feature isn't natively supported. Instead, you need to use the operating system's cron jobs, which adds complexity as to how you expose this task to be executed in a cron job, or how do you debug it when it's not running within the platform's tooling. + +Medusa removes this overhead by supporting this feature natively with scheduled jobs. A scheduled job is an asynchronous function that the Medusa application runs at the interval you specify during the Medusa application's runtime. Your efforts are only spent on implementing the functionality performed by the job, such as syncing products to an ERP. + + + +- You want the action to execute at a specified schedule while the Medusa application **isn't** running. Instead, use the operating system's equivalent of a cron job. +- You want to execute the action once when the application loads. Use [loaders](../loaders/page.mdx) instead. +- You want to execute the action if an event occurs. Use [subscribers](../events-and-subscribers/page.mdx) instead. + + --- ## How to Create a Scheduled Job? -A scheduled job is created in a TypeScript or JavaScript file under the `src/jobs` directory. +You create a scheduled job in a TypeScript or JavaScript file under the `src/jobs` directory. The file exports the asynchronous function to run, and the configurations indicating the schedule to run the function. For example, create the file `src/jobs/hello-world.ts` with the following content: -```ts title="src/jobs/hello-world.ts" -// the scheduled-job function -export default function () { - console.log("Time to say hello world!") +export const highlights = [ + ["4", "greetingJob", "The scheduled job function to execute at a specified interval."] + ["4", "container", "Receive the Medusa container as a parameter"], + ["5", "logger", "Resolve the logger from the container"], + ["10", "config", "The scheduled job's configurations."], + ["11", "name", "The job's unique name"], + ["12", "schedule", "The schedule to run the job on."] +] + +```ts title="src/jobs/hello-world.ts" highlights={highlights} +import { MedusaContainer } from "@medusajs/framework/types" +import { ContainerRegistrationKeys } from "@medusajs/framework/utils" + +export default async function greetingJob(container: MedusaContainer) { + const logger = container.resolve(ContainerRegistrationKeys.LOGGER) + + logger.info("Greeting!") } -// the job's configurations export const config = { - name: "every-minute-message", - // execute every minute + name: "greeting-every-minute", schedule: "* * * * *", } - ``` -A scheduled job file must export: +You export an asynchronous function that receives the [Medusa container](../medusa-container/page.mdx) as a parameter. In the function, you resolve the [Logger utility](../../debugging-and-testing/logging/page.mdx) from the Medusa container and log a message. -- A function to be executed whenever it’s time to run the scheduled job. -- A configuration object defining the job. It has two properties: - - `name`: a unique name for the job. - - `schedule`: a [cron expression](https://crontab.guru/) specifying when to run the job. +You also export a `config` object that has the following properties: -This scheduled job executes every minute and logs into the terminal `Time to say hello world!`. +- `name`: A unique name for the job. +- `schedule`: A string that holds a [cron expression](https://crontab.guru/) indicating the schedule to run the job. -### Test Scheduled Jobs +This scheduled job executes every minute and logs into the terminal `Greeting!`. + +### Test the Scheduled Job To test out your scheduled job, start the Medusa application: @@ -55,66 +75,34 @@ npm run dev After a minute, the following message will be logged to the terminal: ```bash -Time to say hello world! +info: Greeting! ``` --- -## When to Use Scheduled Jobs +## Example: Sync Products Once a Day - +In this section, you'll find a brief example of how you use a scheduled job to sync products to a third-party service. -- You're executing an action at a specified time interval during application runtime. -- The action must be executed automatically. +When implementing flows spanning across systems or [modules](../modules/page.mdx), you use [workflows](../workflows/page.mdx). A workflow is a task made up of a series of steps, and you construct it like you would a regular function, but it's a special function that supports rollback mechanism in case of errors, background execution, and more. - +You can learn how to create a workflow in [this chapter](../workflows/page.mdx), but this example assumes you already have a `syncProductToErpWorkflow` implemented. To execute this workflow once a day, create a scheduled job at `src/jobs/sync-products.ts` with the following content: - +```ts title="src/jobs/sync-products.ts" +import { MedusaContainer } from "@medusajs/framework/types" +import { syncProductToErpWorkflow } from "../workflows/sync-products-to-erp" -- You want the action to execute at a specified time interval while the Medusa application **isn't** running. Instead, use the operating system's equivalent of a cron job. -- You want to execute the action once. Use loaders instead. -- You want to execute the action if an event occurs. Use subscribers instead. - - - ---- - -## Resolve Resources - -The scheduled job function receives a `container` parameter, which is the Medusa container. Use it to resolve resources in your Medusa application, such as services. - -For example: - -export const highlights = [ - ["11", "resolve", "Resolve the Product Module's main service."], - ["11", "Modules.PRODUCT", "The module's registration name imported from `@medusajs/framework/utils`."] -] - -```ts title="src/jobs/hello-world.ts" highlights={highlights} -import { - IProductModuleService, - MedusaContainer, -} from "@medusajs/framework/types" -import { Modules } from "@medusajs/framework/utils" - -export default async function myCustomJob( - container: MedusaContainer -) { - const productModuleService: IProductModuleService = - container.resolve(Modules.PRODUCT) - - const [, count] = await productModuleService.listAndCountProducts() - - console.log( - `Time to check products! You have ${count} product(s)` - ) +export default async function syncProductsJob(container: MedusaContainer) { + await syncProductToErpWorkflow(container) + .run() } export const config = { - name: "every-minute-message", - // execute every minute - schedule: "* * * * *", + name: "sync-products-job", + schedule: "0 0 * * *", } ``` -In the scheduled job function, you resolve the Product Module's main service and retrieve the number of products in the store, then log the number in the terminal. \ No newline at end of file +In the scheduled job function, you execute the `syncProductToErpWorkflow` by invoking it and passing it the container, then invoking the `run` method. You also specify in the exported configurations the schedule `0 0 * * *` which indicates midnight time of every day. + +The next time you start the Medusa application, it will run this job every day at midnight. diff --git a/www/apps/book/generated/edit-dates.mjs b/www/apps/book/generated/edit-dates.mjs index 7f2f8ec26c..7f72f7f20c 100644 --- a/www/apps/book/generated/edit-dates.mjs +++ b/www/apps/book/generated/edit-dates.mjs @@ -1,5 +1,5 @@ export const generatedEditDates = { - "app/learn/basics/scheduled-jobs/page.mdx": "2024-09-30T08:43:53.132Z", + "app/learn/basics/scheduled-jobs/page.mdx": "2024-11-26T11:50:10.302Z", "app/learn/basics/workflows/page.mdx": "2024-09-30T08:43:53.132Z", "app/learn/deployment/page.mdx": "2024-11-25T14:32:44.949Z", "app/learn/page.mdx": "2024-09-03T07:09:09.034Z",