Adds a jobs queue to Payload.
- [x] Docs, w/ examples for Vercel Cron, additional services
- [x] Type the `job` using GeneratedTypes in `JobRunnerArgs`
(@AlessioGr)
- [x] Write the `runJobs` function
- [x] Allow for some type of `payload.runTask`
- [x] Open up a new bin script for running jobs
- [x] Determine strategy for runner endpoint to either await jobs
successfully or return early and stay open until job work completes
(serverless ramifications here)
- [x] Allow for job runner to accept how many jobs to run in one
invocation
- [x] Make a Payload local API method for creating a new job easily
(payload.createJob) or similar which is strongly typed (@AlessioGr)
- [x] Make `payload.runJobs` or similar (@AlessioGr)
- [x] Write tests for retrying up to max retries for a given step
- [x] Write tests for dynamic import of a runner
The shape of the config should permit the definition of steps separate
from the job workflows themselves.
```js
const config = {
// Not sure if we need this property anymore
queues: {
},
// A job is an instance of a workflow, stored in DB
// and triggered by something at some point
jobs: {
// Be able to override the jobs collection
collectionOverrides: () => {},
// Workflows are groups of tasks that handle
// the flow from task to task.
// When defined on the config, they are considered as predefined workflows
// BUT - in the future, we'll allow for UI-based workflow definition as well.
workflows: [
{
slug: 'job-name',
// Temporary name for this
// should be able to pass function
// or path to it for Node to dynamically import
controlFlowInJS: '/my-runner.js',
// Temporary name as well
// should be able to eventually define workflows
// in UI (meaning they need to be serialized in JSON)
// Should not be able to define both control flows
controlFlowInJSON: [
{
task: 'myTask',
next: {
// etc
}
}
],
// Workflows take input
// which are a group of fields
input: [
{
name: 'post',
type: 'relationship',
relationTo: 'posts',
maxDepth: 0,
required: true,
},
{
name: 'message',
type: 'text',
required: true,
},
],
},
],
// Tasks are defined separately as isolated functions
// that can be retried on fail
tasks: [
{
slug: 'myTask',
retries: 2,
// Each task takes input
// Used to auto-type the task func args
input: [
{
name: 'post',
type: 'relationship',
relationTo: 'posts',
maxDepth: 0,
required: true,
},
{
name: 'message',
type: 'text',
required: true,
},
],
// Each task takes output
// Used to auto-type the function signature
output: [
{
name: 'success',
type: 'checkbox',
}
],
onSuccess: () => {},
onFail: () => {},
run: myRunner,
},
]
}
}
```
### `payload.createJob`
This function should allow for the creation of jobs based on either a
workflow (group of tasks) or an individual task.
To create a job using a workflow:
```js
const job = await payload.createJob({
// Accept the `name` of a workflow so we can match to either a
// code-based workflow OR a workflow defined in the DB
// Should auto-type the input
workflowName: 'myWorkflow',
input: {
// typed to the args of the workflow by name
}
})
```
To create a job using a task:
```js
const job = await payload.createJob({
// Accept the `name` of a task
task: 'myTask',
input: {
// typed to the args of the task by name
}
})
```
---------
Co-authored-by: Alessio Gravili <alessio@gravili.de>
Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
582 lines
12 KiB
TypeScript
582 lines
12 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
|
|
/**
|
|
* This is a list of all possible imports from Payload 2.x
|
|
*
|
|
* All of these should either resolve here
|
|
*
|
|
* OR
|
|
*
|
|
* Be documented in the migration guide and breaking changes doc
|
|
*/
|
|
|
|
import payload from 'payload'
|
|
import {
|
|
CollectionPermission,
|
|
FieldPermissions,
|
|
GlobalPermission,
|
|
IncomingAuthType,
|
|
Permission,
|
|
Permissions,
|
|
User,
|
|
VerifyConfig,
|
|
} from 'payload/auth'
|
|
import {
|
|
Banner,
|
|
Button,
|
|
Check,
|
|
Chevron,
|
|
ErrorPill,
|
|
Menu,
|
|
MinimalTemplate,
|
|
Pill,
|
|
Popup,
|
|
Search,
|
|
ShimmerEffect,
|
|
Tooltip,
|
|
X,
|
|
} from 'payload/components'
|
|
import {
|
|
Access,
|
|
AccessArgs,
|
|
AccessResult,
|
|
AdminView,
|
|
AdminViewComponent,
|
|
AdminViewConfig,
|
|
AdminViewProps,
|
|
baseBlockFields,
|
|
baseIDField,
|
|
BaseLocalizationConfig,
|
|
buildConfig,
|
|
Config,
|
|
defaults,
|
|
EditView,
|
|
EditViewConfig,
|
|
EmailOptions,
|
|
EmailTransport,
|
|
EmailTransportOptions,
|
|
Endpoint,
|
|
EntityDescription,
|
|
FieldTypes,
|
|
GeneratePreviewURL,
|
|
GraphQLExtension,
|
|
hasTransport,
|
|
hasTransportOptions,
|
|
InitOptions,
|
|
LivePreviewConfig,
|
|
Locale,
|
|
LocalizationConfig,
|
|
LocalizationConfigWithLabels,
|
|
LocalizationConfigWithNoLabels,
|
|
PayloadHandler,
|
|
Plugin,
|
|
sanitizeConfig,
|
|
SanitizedConfig,
|
|
SanitizedLocalizationConfig,
|
|
sanitizeFields,
|
|
} from 'payload/config'
|
|
import {
|
|
BaseDatabaseAdapter,
|
|
BeginTransaction,
|
|
combineQueries,
|
|
CommitTransaction,
|
|
Connect,
|
|
Count,
|
|
CountArgs,
|
|
Create,
|
|
CreateArgs,
|
|
createDatabaseAdapter,
|
|
CreateGlobal,
|
|
CreateGlobalArgs,
|
|
CreateGlobalVersion,
|
|
CreateGlobalVersionArgs,
|
|
CreateMigration,
|
|
createMigration,
|
|
CreateVersion,
|
|
CreateVersionArgs,
|
|
DBIdentifierName,
|
|
DeleteMany,
|
|
DeleteManyArgs,
|
|
DeleteOne,
|
|
DeleteOneArgs,
|
|
DeleteVersions,
|
|
DeleteVersionsArgs,
|
|
Destroy,
|
|
EntityPolicies,
|
|
Find,
|
|
FindArgs,
|
|
FindGlobal,
|
|
FindGlobalArgs,
|
|
FindGlobalVersions,
|
|
FindGlobalVersionsArgs,
|
|
FindOne,
|
|
FindOneArgs,
|
|
FindVersions,
|
|
FindVersionsArgs,
|
|
flattenWhereToOperators,
|
|
getLocalizedPaths,
|
|
getMigrations,
|
|
Init,
|
|
migrate,
|
|
migrateDown,
|
|
migrateRefresh,
|
|
migrateReset,
|
|
migrateStatus,
|
|
Migration,
|
|
MigrationData,
|
|
migrationsCollection,
|
|
migrationTemplate,
|
|
PaginatedDocs,
|
|
PathToQuery,
|
|
QueryDrafts,
|
|
QueryDraftsArgs,
|
|
readMigrationFiles,
|
|
RollbackTransaction,
|
|
Transaction,
|
|
TypeWithVersion,
|
|
UpdateGlobal,
|
|
UpdateGlobalArgs,
|
|
UpdateGlobalVersion,
|
|
UpdateGlobalVersionArgs,
|
|
UpdateOne,
|
|
UpdateOneArgs,
|
|
UpdateVersion,
|
|
UpdateVersionArgs,
|
|
validateQueryPaths,
|
|
validateSearchParam,
|
|
} from 'payload/database'
|
|
import {
|
|
APIError,
|
|
AuthenticationError,
|
|
DuplicateCollection,
|
|
DuplicateGlobal,
|
|
ErrorDeletingFile,
|
|
FileUploadError,
|
|
Forbidden,
|
|
InvalidConfiguration,
|
|
InvalidFieldName,
|
|
InvalidFieldRelationship,
|
|
LockedAuth,
|
|
MissingCollectionLabel,
|
|
MissingFieldInputOptions,
|
|
MissingFieldType,
|
|
MissingFile,
|
|
NotFound,
|
|
QueryError,
|
|
ValidationError,
|
|
} from 'payload/errors'
|
|
import { buildPaginatedListType, GraphQL } from 'payload/graphql'
|
|
import {
|
|
AccessArgs as AccessArgsType,
|
|
Access as AccessType,
|
|
AllOperations,
|
|
ArrayField,
|
|
AuthOperations,
|
|
BeforeDuplicate,
|
|
Block,
|
|
BlockField,
|
|
CellComponentProps,
|
|
CheckboxField,
|
|
CodeField,
|
|
CollapsibleField,
|
|
Collection,
|
|
CollectionAfterChangeHook,
|
|
CollectionAfterDeleteHook,
|
|
CollectionAfterForgotPasswordHook,
|
|
CollectionAfterLoginHook,
|
|
CollectionAfterOperationHook,
|
|
CollectionAfterReadHook,
|
|
CollectionBeforeChangeHook,
|
|
CollectionBeforeDeleteHook,
|
|
CollectionBeforeLoginHook,
|
|
CollectionBeforeOperationHook,
|
|
CollectionBeforeReadHook,
|
|
CollectionBeforeValidateHook,
|
|
CollectionConfig,
|
|
Condition,
|
|
CreateFormData,
|
|
CustomPublishButtonProps,
|
|
CustomPublishButtonType,
|
|
CustomSaveButtonProps,
|
|
CustomSaveDraftButtonProps,
|
|
Data,
|
|
DateField,
|
|
docHasTimestamps,
|
|
Document,
|
|
EmailField,
|
|
Field,
|
|
FieldAccess,
|
|
FieldAffectingData,
|
|
fieldAffectsData,
|
|
FieldBase,
|
|
fieldHasMaxDepth,
|
|
fieldHasSubFields,
|
|
FieldHook,
|
|
FieldHookArgs,
|
|
fieldIsArrayType,
|
|
fieldIsBlockType,
|
|
fieldIsGroupType,
|
|
fieldIsLocalized,
|
|
fieldIsPresentationalOnly,
|
|
FieldPresentationalOnly,
|
|
Fields,
|
|
fieldSupportsMany,
|
|
FieldWithMany,
|
|
FieldWithMaxDepth,
|
|
FieldWithPath,
|
|
FieldWithRichTextRequiredEditor,
|
|
FieldWithSubFields,
|
|
FileData,
|
|
FilterOptions,
|
|
FilterOptionsProps,
|
|
FormField,
|
|
FormFieldsContext,
|
|
GlobalAfterChangeHook,
|
|
GlobalAfterReadHook,
|
|
GlobalBeforeChangeHook,
|
|
GlobalBeforeReadHook,
|
|
GlobalBeforeValidateHook,
|
|
GlobalConfig,
|
|
GroupField,
|
|
HookName,
|
|
ImageSize,
|
|
IncomingUploadType,
|
|
JSONField,
|
|
Labels,
|
|
NamedTab,
|
|
NonPresentationalField,
|
|
NumberField,
|
|
Operation,
|
|
Operator,
|
|
Option,
|
|
optionIsObject,
|
|
optionIsValue,
|
|
OptionObject,
|
|
optionsAreObjects,
|
|
PayloadRequest,
|
|
PointField,
|
|
PolymorphicRelationshipField,
|
|
RadioField,
|
|
RelationshipField,
|
|
RelationshipValue,
|
|
RichTextAdapter,
|
|
RichTextFieldProps,
|
|
RichTextFieldRequiredEditor,
|
|
RichTextField as RichTextFieldType,
|
|
RowAdmin,
|
|
RowField,
|
|
RowLabel,
|
|
SanitizedCollectionConfig,
|
|
SanitizedGlobalConfig,
|
|
SelectField,
|
|
SingleRelationshipField,
|
|
Tab,
|
|
TabAsField,
|
|
tabHasName,
|
|
TabsAdmin,
|
|
TabsField,
|
|
TextareaField,
|
|
TextField,
|
|
TypeWithID,
|
|
UIField,
|
|
UnnamedTab,
|
|
UploadField,
|
|
Validate,
|
|
ValidateOptions,
|
|
validOperators,
|
|
valueIsValueWithRelation,
|
|
ValueWithRelation,
|
|
VersionOperations,
|
|
Where,
|
|
WhereField,
|
|
} from 'payload/types'
|
|
import {
|
|
afterReadPromise,
|
|
afterReadTraverseFields,
|
|
combineMerge,
|
|
configToJSONSchema,
|
|
createArrayFromCommaDelineated,
|
|
deepCopyObject,
|
|
deepMerge,
|
|
entityToJSONSchema,
|
|
extractTranslations,
|
|
fieldSchemaToJSON,
|
|
fieldsToJSONSchema,
|
|
flattenTopLevelFields,
|
|
formatLabels,
|
|
formatNames,
|
|
getCollectionIDFieldTypes,
|
|
getIDType,
|
|
getTranslation,
|
|
i18nInit,
|
|
isValidID,
|
|
toWords,
|
|
withMergedProps,
|
|
withNullableJSONSchemaType,
|
|
} from 'payload/utilities'
|
|
import {
|
|
buildVersionCollectionFields,
|
|
buildVersionGlobalFields,
|
|
deleteCollectionVersions,
|
|
enforceMaxVersions,
|
|
getLatestCollectionVersion,
|
|
getLatestGlobalVersion,
|
|
saveVersion,
|
|
} from 'payload/versions'
|
|
|
|
/**
|
|
* Plugins
|
|
*/
|
|
|
|
import {
|
|
Args,
|
|
MigrateDownArgs,
|
|
MigrateUpArgs,
|
|
MongooseAdapter,
|
|
mongooseAdapter,
|
|
} from '@payloadcms/db-mongodb'
|
|
import {
|
|
MigrateDownArgs as MigrateDownArgsPg,
|
|
MigrateUpArgs as MigrateUpArgsPg,
|
|
postgresAdapter,
|
|
} from '@payloadcms/db-postgres'
|
|
import { handleMessage, mergeData, ready, subscribe, unsubscribe } from '@payloadcms/live-preview'
|
|
import { useLivePreview } from '@payloadcms/live-preview-react'
|
|
import { createKey, getStorageClient, payloadCloud } from '@payloadcms/payload-cloud'
|
|
import { cloudStorage } from '@payloadcms/plugin-cloud-storage'
|
|
import { fields, getPaymentTotal } from '@payloadcms/plugin-form-builder'
|
|
import {
|
|
BeforeEmail,
|
|
BlockConfig,
|
|
CountryField,
|
|
Email,
|
|
FieldConfig,
|
|
FieldsConfig,
|
|
FieldValues,
|
|
Form,
|
|
FormattedEmail,
|
|
CheckboxField as FormBuilderCheckboxField,
|
|
EmailField as FormBuilderEmailField,
|
|
SelectField as FormBuilderSelectField,
|
|
TextField as FormBuilderTextField,
|
|
FormFieldBlock,
|
|
FormSubmission,
|
|
HandlePayment,
|
|
isValidBlockConfig,
|
|
MessageField,
|
|
PaymentField,
|
|
PaymentFieldConfig,
|
|
PluginConfig,
|
|
PriceCondition,
|
|
Redirect,
|
|
SelectFieldOption,
|
|
StateField,
|
|
SubmissionValue,
|
|
TextAreaField,
|
|
} from '@payloadcms/plugin-form-builder/types'
|
|
import nestedDocs from '@payloadcms/plugin-nested-docs'
|
|
import { createBreadcrumbsField, createParentField } from '@payloadcms/plugin-nested-docs/fields'
|
|
import {
|
|
Breadcrumb,
|
|
GenerateLabel,
|
|
GenerateURL,
|
|
PluginConfig as NestedDocsPluginConfig,
|
|
} from '@payloadcms/plugin-nested-docs/types'
|
|
import redirects from '@payloadcms/plugin-redirects'
|
|
import { PluginConfig as RedirectsPluginConfig } from '@payloadcms/plugin-redirects/types'
|
|
|
|
// Skip plugin-sentry
|
|
|
|
import search from '@payloadcms/plugin-search'
|
|
import {
|
|
BeforeSync,
|
|
DocToSync,
|
|
SearchConfig,
|
|
SyncWithSearch,
|
|
} from '@payloadcms/plugin-search/types'
|
|
import seo from '@payloadcms/plugin-seo'
|
|
import {
|
|
GenerateDescription,
|
|
GenerateImage,
|
|
GenerateTitle,
|
|
Meta,
|
|
GenerateURL as seoGenerateURL,
|
|
PluginConfig as SeoPluginConfig,
|
|
} from '@payloadcms/plugin-seo/types'
|
|
import stripePlugin from '@payloadcms/plugin-stripe'
|
|
import {
|
|
FieldSyncConfig,
|
|
SanitizedStripeConfig,
|
|
StripeConfig,
|
|
StripeProxy,
|
|
StripeWebhookHandler,
|
|
StripeWebhookHandlers,
|
|
SyncConfig,
|
|
} from '@payloadcms/plugin-stripe/types'
|
|
import {
|
|
$createAutoLinkNode,
|
|
$createBlockNode,
|
|
$createLinkNode,
|
|
$createRelationshipNode,
|
|
$createUploadNode,
|
|
$isAutoLinkNode,
|
|
$isBlockNode,
|
|
$isLinkNode,
|
|
$isRelationshipNode,
|
|
$isUploadNode,
|
|
AdapterProps,
|
|
addSwipeDownListener,
|
|
addSwipeLeftListener,
|
|
addSwipeRightListener,
|
|
addSwipeUpListener,
|
|
AlignFeature,
|
|
AutoLinkNode,
|
|
BlockFields,
|
|
BlockNode,
|
|
BlockQuoteFeature,
|
|
BlocksFeature,
|
|
BlocksFeatureProps,
|
|
BoldTextFeature,
|
|
CAN_USE_DOM,
|
|
CheckListFeature,
|
|
cloneDeep,
|
|
consolidateHTMLConverters,
|
|
convertLexicalNodesToHTML,
|
|
convertLexicalToHTML,
|
|
convertSlateNodesToLexical,
|
|
convertSlateToLexical,
|
|
createBlockNode,
|
|
defaultEditorConfig,
|
|
defaultEditorFeatures,
|
|
defaultHTMLConverters,
|
|
defaultRichTextValue,
|
|
defaultSanitizedEditorConfig,
|
|
defaultSlateConverters,
|
|
DETAIL_TYPE_TO_DETAIL,
|
|
DOUBLE_LINE_BREAK,
|
|
EditorConfig,
|
|
EditorConfigProvider,
|
|
ELEMENT_FORMAT_TO_TYPE,
|
|
ELEMENT_TYPE_TO_FORMAT,
|
|
ENABLE_SLASH_MENU_COMMAND,
|
|
Feature,
|
|
FeatureProvider,
|
|
FeatureProviderMap,
|
|
FloatingToolbarSection,
|
|
FloatingToolbarSectionEntry,
|
|
FormatSectionWithEntries,
|
|
getDOMRangeRect,
|
|
getEnabledNodes,
|
|
getSelectedNode,
|
|
HeadingFeature,
|
|
HTMLConverter,
|
|
HTMLConverterFeature,
|
|
HTMLConverterFeatureProps,
|
|
IndentFeature,
|
|
InlineCodeTextFeature,
|
|
invariant,
|
|
IS_ALL_FORMATTING,
|
|
isHTMLElement,
|
|
isPoint,
|
|
ItalicTextFeature,
|
|
joinClasses,
|
|
LexicalBlock,
|
|
lexicalEditor,
|
|
LexicalEditorProps,
|
|
lexicalHTML,
|
|
LexicalPluginToLexicalFeature,
|
|
LexicalRichTextAdapter,
|
|
LinebreakHTMLConverter,
|
|
LinkFeature,
|
|
LinkFeatureProps,
|
|
LinkFields,
|
|
LinkNode,
|
|
loadFeatures,
|
|
LTR_REGEX,
|
|
NodeFormat,
|
|
NodeValidation,
|
|
NON_BREAKING_SPACE,
|
|
OrderedListFeature,
|
|
ParagraphFeature,
|
|
ParagraphHTMLConverter,
|
|
Point,
|
|
PopulationPromise,
|
|
RawUploadPayload,
|
|
Rect,
|
|
RelationshipData,
|
|
RelationshipFeature,
|
|
RelationshipNode,
|
|
ResolvedFeature,
|
|
ResolvedFeatureMap,
|
|
RTL_REGEX,
|
|
SanitizedEditorConfig,
|
|
SanitizedFeatures,
|
|
sanitizeEditorConfig,
|
|
sanitizeFeatures,
|
|
sanitizeUrl,
|
|
SerializedAutoLinkNode,
|
|
SerializedBlockNode,
|
|
SerializedLinkNode,
|
|
SerializedRelationshipNode,
|
|
SerializedUploadNode,
|
|
setFloatingElemPosition,
|
|
setFloatingElemPositionForLinkEditor,
|
|
SlashMenuGroup,
|
|
SlashMenuOption,
|
|
SlateBlockquoteConverter,
|
|
SlateHeadingConverter,
|
|
SlateIndentConverter,
|
|
SlateLinkConverter,
|
|
SlateListItemConverter,
|
|
SlateNode,
|
|
SlateNodeConverter,
|
|
SlateOrderedListConverter,
|
|
SlateRelationshipConverter,
|
|
SlateToLexicalFeature,
|
|
SlateUnknownConverter,
|
|
SlateUnorderedListConverter,
|
|
SlateUploadConverter,
|
|
sortFeaturesForOptimalLoading,
|
|
StrikethroughTextFeature,
|
|
SubscriptTextFeature,
|
|
SuperscriptTextFeature,
|
|
TestRecorderFeature,
|
|
TEXT_MODE_TO_TYPE,
|
|
TEXT_TYPE_TO_FORMAT,
|
|
TEXT_TYPE_TO_MODE,
|
|
TextDropdownSectionWithEntries,
|
|
TextHTMLConverter,
|
|
TOGGLE_LINK_COMMAND,
|
|
TreeViewFeature,
|
|
UnderlineTextFeature,
|
|
UnorderedListFeature,
|
|
UploadData,
|
|
UploadFeature,
|
|
UploadFeatureProps,
|
|
UploadNode,
|
|
useEditorConfigContext,
|
|
validateUrl,
|
|
} from '@payloadcms/richtext-lexical'
|
|
import {
|
|
defaultEditorLexicalConfig,
|
|
RichTextCell,
|
|
RichTextField,
|
|
ToolbarButton,
|
|
ToolbarDropdown,
|
|
} from '@payloadcms/richtext-lexical/components'
|
|
import {
|
|
AdapterArguments,
|
|
ElementButton,
|
|
ElementNode,
|
|
FieldProps,
|
|
LeafButton,
|
|
nodeIsTextNode,
|
|
RichTextCustomElement,
|
|
RichTextCustomLeaf,
|
|
RichTextElement,
|
|
RichTextLeaf,
|
|
slateEditor,
|
|
TextNode,
|
|
toggleElement,
|
|
} from '@payloadcms/richtext-slate'
|