@lucidcms/core
Version:
The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.
1 lines • 9.67 kB
Source Map (JSON)
{"version":3,"file":"cron.mjs","names":["cliLogger","getCronJobs"],"sources":["../../../../src/libs/cli/commands/cron.ts"],"sourcesContent":["import { select } from \"@inquirer/prompts\";\nimport type { Config } from \"../../../types.js\";\nimport createServiceContext from \"../../../utils/services/create-service-context.js\";\nimport serviceWrapper from \"../../../utils/services/service-wrapper.js\";\nimport getConfigPath from \"../../config/get-config-path.js\";\nimport loadConfigFile from \"../../config/load-config-file.js\";\nimport type { DatabaseConnection } from \"../../db/types.js\";\nimport {\n\tdestroyEmailAdapter,\n\tgetInitializedEmailAdapter,\n} from \"../../email/lifecycle.js\";\nimport type { EmailAdapterInstance } from \"../../email/types.js\";\nimport { copy } from \"../../i18n/index.js\";\nimport prepareTranslations from \"../../i18n/prepare-translations.js\";\nimport type { TranslationStore } from \"../../i18n/types.js\";\nimport {\n\tdestroyKVAdapter,\n\tgetInitializedKVAdapter,\n} from \"../../kv/lifecycle.js\";\nimport type { KVAdapterInstance } from \"../../kv/types.js\";\nimport {\n\tstartLoggerBuffering,\n\tstopLoggerBuffering,\n} from \"../../logger/index.js\";\nimport {\n\tdestroyMediaAdapter,\n\tgetInitializedMediaAdapter,\n} from \"../../media/lifecycle.js\";\nimport type { MediaAdapterInstance } from \"../../media/types.js\";\nimport passthroughQueueAdapter from \"../../queue/adapters/passthrough.js\";\nimport getCronJobs, { type CronJobKey } from \"../../runtime/cron-jobs.js\";\nimport type {\n\tAdapterRuntimeContext,\n\tEnvironmentVariables,\n} from \"../../runtime/types.js\";\nimport cliLogger from \"../logger.js\";\nimport validateEnvVars from \"../services/validate-env-vars.js\";\n\nconst cronCommand = async (jobName?: string) => {\n\tlet config: Config | undefined;\n\tlet translationStore: TranslationStore | undefined;\n\tlet env: EnvironmentVariables | undefined;\n\tlet runtimeContext: AdapterRuntimeContext | undefined;\n\tlet kv: KVAdapterInstance | undefined;\n\tlet media: MediaAdapterInstance | null | undefined;\n\tlet email: EmailAdapterInstance | undefined;\n\tlet database: DatabaseConnection | undefined;\n\n\tconst cleanupAdapters = async () => {\n\t\tif (config && translationStore) {\n\t\t\tawait Promise.allSettled([\n\t\t\t\tdatabase?.destroy(),\n\t\t\t\tdestroyKVAdapter(kv, { config, env, runtimeContext }),\n\t\t\t\tdestroyMediaAdapter(media, { config, env, runtimeContext }),\n\t\t\t\tdestroyEmailAdapter(email, { config, env, runtimeContext }),\n\t\t\t]);\n\t\t}\n\t\tdatabase = undefined;\n\t\tkv = undefined;\n\t\tmedia = undefined;\n\t\temail = undefined;\n\t};\n\n\ttry {\n\t\tstartLoggerBuffering();\n\t\tconst startTime = cliLogger.startTimer();\n\t\tconst cronJobs = getCronJobs();\n\n\t\t//* resolve which cron job to run\n\t\tlet selectedJob: CronJobKey;\n\n\t\tif (jobName) {\n\t\t\tif (!(jobName in cronJobs)) {\n\t\t\t\tcliLogger.error(`Unknown cron job \"${jobName}\". Available jobs:`);\n\t\t\t\tfor (const key of Object.keys(cronJobs)) {\n\t\t\t\t\tcliLogger.log(` ${key}`, { symbol: \"bullet\" });\n\t\t\t\t}\n\t\t\t\tawait stopLoggerBuffering();\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\tselectedJob = jobName as CronJobKey;\n\t\t} else {\n\t\t\ttry {\n\t\t\t\tselectedJob = await select<CronJobKey>({\n\t\t\t\t\tmessage: \"Select a cron job to run:\",\n\t\t\t\t\tchoices: Object.entries(cronJobs).map(([key, value]) => ({\n\t\t\t\t\t\tname: value.label,\n\t\t\t\t\t\tvalue: key as CronJobKey,\n\t\t\t\t\t})),\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof Error && error.name === \"ExitPromptError\") {\n\t\t\t\t\tawait stopLoggerBuffering();\n\t\t\t\t\tprocess.exit(0);\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tconst job = cronJobs[selectedJob];\n\n\t\tcliLogger.info(`Running cron job: ${job.label}`);\n\n\t\t//* load config\n\t\tconst configPath = getConfigPath(process.cwd());\n\t\tconst configRes = await loadConfigFile({\n\t\t\tpath: configPath,\n\t\t\tprepareRuntime: true,\n\t\t});\n\t\tconfig = configRes.config;\n\t\truntimeContext = configRes.runtimeContext;\n\t\ttranslationStore = (\n\t\t\tawait prepareTranslations({\n\t\t\t\tconfig,\n\t\t\t\tprojectRoot: configRes.projectRoot,\n\t\t\t})\n\t\t).translationStore;\n\t\tenv = configRes.env;\n\t\tconst envValid = await validateEnvVars({\n\t\t\tenvSchema: configRes.envSchema,\n\t\t\tenv: configRes.env,\n\t\t});\n\t\tif (!envValid) {\n\t\t\tawait stopLoggerBuffering();\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\t//* create a passthrough queue adapter with immediate execution enabled so\n\t\t//* any jobs pushed to the queue by the cron are executed straight away\n\t\tconst queue = passthroughQueueAdapter();\n\t\tdatabase = await configRes.config.db.connect(env);\n\t\tkv = await getInitializedKVAdapter(configRes.config, {\n\t\t\tenv,\n\t\t\truntimeContext,\n\t\t});\n\t\tmedia = await getInitializedMediaAdapter(configRes.config, {\n\t\t\tenv,\n\t\t\truntimeContext,\n\t\t});\n\t\temail = await getInitializedEmailAdapter(configRes.config, {\n\t\t\tenv,\n\t\t\truntimeContext,\n\t\t});\n\n\t\tconst serviceContext = createServiceContext({\n\t\t\tconfig: configRes.config,\n\t\t\tdatabase,\n\t\t\ttranslationStore,\n\t\t\tenv,\n\t\t\truntimeContext,\n\t\t\tqueue,\n\t\t\tkv,\n\t\t\tmedia,\n\t\t\temail,\n\t\t});\n\n\t\t//* run the selected cron job with retry support\n\t\tconst maxRetries = 3;\n\t\tlet lastError: string | undefined;\n\t\tlet success = false;\n\n\t\tfor (let attempt = 1; attempt <= maxRetries; attempt++) {\n\t\t\tconst result = await serviceWrapper(job.fn, {\n\t\t\t\ttransaction: job.transaction,\n\t\t\t\tlogError: true,\n\t\t\t\tdefaultError: {\n\t\t\t\t\ttype: \"cron\",\n\t\t\t\t\tname: copy(\"server:core.cron.job.error.name\"),\n\t\t\t\t\tmessage: job.error,\n\t\t\t\t},\n\t\t\t})(serviceContext);\n\n\t\t\tif (!result.error) {\n\t\t\t\tsuccess = true;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tlastError =\n\t\t\t\tserviceContext.translate.english(result.error.message) ??\n\t\t\t\t\"Unknown error\";\n\n\t\t\tif (attempt < maxRetries) {\n\t\t\t\tcliLogger.warn(\n\t\t\t\t\t`Cron job \"${job.label}\" failed (attempt ${attempt}/${maxRetries}), retrying...`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (!success) {\n\t\t\tcliLogger.error(\n\t\t\t\t`Cron job \"${job.label}\" failed after ${maxRetries} attempts:`,\n\t\t\t\tlastError ?? \"Unknown error\",\n\t\t\t);\n\t\t\tawait cleanupAdapters();\n\t\t\tawait stopLoggerBuffering();\n\t\t\tprocess.exit(1);\n\t\t}\n\n\t\tconst endTime = startTime();\n\t\tcliLogger.log(\n\t\t\tcliLogger.createBadge(\"LUCID CMS\"),\n\t\t\t`Cron job \"${job.label}\" completed`,\n\t\t\tcliLogger.color.green(\"successfully\"),\n\t\t\t\"in\",\n\t\t\tcliLogger.color.green(cliLogger.formatMilliseconds(endTime)),\n\t\t\t{\n\t\t\t\tspaceAfter: true,\n\t\t\t\tspaceBefore: true,\n\t\t\t},\n\t\t);\n\n\t\tawait cleanupAdapters();\n\t\tawait stopLoggerBuffering();\n\t\tprocess.exit(0);\n\t} catch (error) {\n\t\tawait cleanupAdapters();\n\t\tif (error instanceof Error) {\n\t\t\tcliLogger.errorInstance(error, \"Failed to run cron job\");\n\t\t} else {\n\t\t\tcliLogger.error(\"Failed to run cron job\", \"Unknown error\");\n\t\t}\n\t\tawait stopLoggerBuffering();\n\t\tprocess.exit(1);\n\t}\n};\n\nexport default cronCommand;\n"],"mappings":"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"}