-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
426 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<template> | ||
<Title>Edit {{cronjob.props?.id}}</Title> | ||
<PanelFrame :title="'Edit '+cronjob.props?.id" section="Cron Jobs"> | ||
<template #left> | ||
<PanelNav :links="links" /> | ||
</template> | ||
<template #content> | ||
<FieldsetNav v-if="cronjob.props"> | ||
<FieldsetItem name="Properties"> | ||
|
||
<FormInput name="schedule" type="text" v-model="cronjob.props.schedule" required label="Schedule" @change="cronjob.save('schedule')" class="mb-4" /> | ||
<FormInput name="handler" type="select" :options="cronjob.options?.handler" v-model="cronjob.props.handler" required label="Handler" @change="cronjob.save('handler')" class="mb-4" /> | ||
<FormInput name="params" type="textarea" v-model="computedParams" label="Params" @change="cronjob.save('params')" class="mb-4" /> | ||
<FormInput name="enabled" type="select" :options="cronjob.options?.enabled" v-model="cronjob.props.enabled" label="Enabled" @change="cronjob.save('enabled')" class="mb-4" /> | ||
<FormInput name="note" type="textarea" v-model="cronjob.props.note" label="Note" @change="cronjob.save('note')" class="mb-4" /> | ||
</FieldsetItem> | ||
|
||
<FieldsetItem name="Statistics"> | ||
|
||
<div class="mb-4"><b>Id</b>: {{cronjob.props?.id}} <CopyToClipboard :text="cronjob.props?.id" size="xs" /></div> | ||
|
||
<div class="mb-4"><b>Created At</b>: {{formatDateTime(cronjob.props.createdAt)}}</div> | ||
|
||
<div class="mb-4"><b>Updated At</b>: {{formatDateTime(cronjob.props.updatedAt)}}</div> | ||
|
||
</FieldsetItem> | ||
|
||
<FieldsetItem name="Actions"> | ||
<Button @mousedown="cronjob.delete()" severity="danger" class="mr-2 mb-2" title="Delete" alt="Delete Cron Job"><Icon name="ph:trash" class="mr-1"/> Delete</Button> | ||
</FieldsetItem> | ||
</FieldsetNav> | ||
</template> | ||
</PanelFrame> | ||
</template> | ||
|
||
<script setup> | ||
definePageMeta({ | ||
middleware: ['auth', 'admin'] | ||
}); | ||
const route = useRoute(); | ||
const notify = useNotify(); | ||
const id = route.params.id.toString(); | ||
const cronjob = useVingRecord({ | ||
id, | ||
fetchApi: `/api/${useRestVersion()}/cronjob/${id}`, | ||
createApi: `/api/${useRestVersion()}/cronjob`, | ||
query: { includeMeta: true, includeOptions: true }, | ||
onUpdate() { | ||
notify.success('Updated Cron Job.'); | ||
}, | ||
async onDelete() { | ||
await navigateTo('/cronjob'); | ||
}, | ||
}); | ||
await cronjob.fetch() | ||
const computedParams = computed({ | ||
get() { | ||
return JSON.stringify(cronjob.props.params); | ||
}, | ||
set(value) { | ||
cronjob.props.params = JSON.parse(value); | ||
} | ||
}); | ||
onBeforeRouteLeave(() => cronjob.dispose()); | ||
const links = useAdminLinks(); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
<template> | ||
<Title>Cron Jobs</Title> | ||
<PanelFrame title="Cron Jobs"> | ||
<template #left> | ||
<PanelNav :links="links" /> | ||
</template> | ||
<template #content> | ||
<PanelZone title="Existing Cron Jobs"> | ||
<DataTable :value="cronjobs.records" stripedRows @sort="(e) => cronjobs.sortDataTable(e)"> | ||
|
||
<Column field="props.schedule" header="Schedule" sortable></Column> | ||
<Column field="props.handler" header="Handler" sortable></Column> | ||
<Column field="props.params" header="Params" sortable></Column> | ||
<Column field="props.enabled" header="Enabled" sortable> | ||
<template #body="slotProps"> | ||
{{ enum2label(slotProps.data.props.enabled, cronjobs.propsOptions.enabled) }} | ||
</template> | ||
</Column> | ||
<Column header="Manage"> | ||
<template #body="slotProps"> | ||
<ManageButton severity="primary" :items="[ | ||
{ icon:'ph:pencil', label:'Edit', to:`/cronjob/${slotProps.data.props.id}/edit`}, | ||
{ icon:'ph:trash', label:'Delete', action:slotProps.data.delete} | ||
]" /> | ||
</template> | ||
</Column> | ||
</DataTable> | ||
<Pager :kind="cronjobs" /> | ||
</PanelZone> | ||
<PanelZone title="Create Cron Job"> | ||
<Form :send="() => cronjobs.create()"> | ||
|
||
<FormInput name="schedule" type="text" v-model="cronjobs.new.schedule" required label="Schedule" class="mb-4" /> | ||
<FormInput name="handler" type="select" v-model="cronjobs.new.handler" :options="cronjobs.propsOptions?.handler" required label="Handler" class="mb-4" /> | ||
<div> | ||
<Button type="submit" class="w-auto" severity="success"> | ||
<Icon name="ph:plus" class="mr-1"/> Create Cron Job | ||
</Button> | ||
</div> | ||
</Form> | ||
</PanelZone> | ||
</template> | ||
</PanelFrame> | ||
</template> | ||
|
||
<script setup> | ||
definePageMeta({ | ||
middleware: ['auth', 'admin'] | ||
}); | ||
const cronjobs = useVingKind({ | ||
listApi: `/api/${useRestVersion()}/cronjob`, | ||
createApi: `/api/${useRestVersion()}/cronjob`, | ||
query: { includeMeta: true, sortBy: 'schedule', sortOrder: 'asc' }, | ||
newDefaults: { schedule: '* * * * *', handler: 'Test', enabled: true }, | ||
}); | ||
await Promise.all([ | ||
cronjobs.search(), | ||
cronjobs.fetchPropsOptions(), | ||
]); | ||
onBeforeRouteLeave(() => cronjobs.dispose()); | ||
const links = useAdminLinks(); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { useKind } from '#ving/record/utils.mjs'; | ||
import { obtainSession, describeParams } from '#ving/utils/rest.mjs'; | ||
import {defineEventHandler, getRouterParams} from 'h3'; | ||
export default defineEventHandler(async (event) => { | ||
const cronjobs = await useKind('CronJob'); | ||
const { id } = getRouterParams(event); | ||
const cronjob = await cronjobs.findOrDie(id); | ||
const session = obtainSession(event); | ||
await cronjob.canEdit(session); | ||
await cronjob.delete(); | ||
return cronjob.describe(describeParams(event, session)); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { useKind } from '#ving/record/utils.mjs'; | ||
import { describeParams } from '#ving/utils/rest.mjs'; | ||
import {defineEventHandler, getRouterParams} from 'h3'; | ||
export default defineEventHandler(async (event) => { | ||
const cronjobs = await useKind('CronJob'); | ||
const { id } = getRouterParams(event); | ||
const cronjob = await cronjobs.findOrDie(id); | ||
return cronjob.describe(describeParams(event)); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { useKind } from '#ving/record/utils.mjs'; | ||
import { describeParams, obtainSession, getBody } from '#ving/utils/rest.mjs'; | ||
import {defineEventHandler, getRouterParams} from 'h3'; | ||
export default defineEventHandler(async (event) => { | ||
const cronjobs = await useKind('CronJob'); | ||
const { id } = getRouterParams(event); | ||
const cronjob = await cronjobs.findOrDie(id); | ||
const session = obtainSession(event); | ||
await cronjob.canEdit(session); | ||
await cronjob.updateAndVerify(await getBody(event), session); | ||
return cronjob.describe(describeParams(event, session)); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { useKind } from '#ving/record/utils.mjs'; | ||
import { describeListParams, describeListWhere } from '#ving/utils/rest.mjs'; | ||
import {defineEventHandler} from 'h3'; | ||
export default defineEventHandler(async (event) => { | ||
const cronjobs = await useKind('CronJob'); | ||
return await cronjobs.describeList(describeListParams(event), describeListWhere(event, cronjobs.describeListFilter())); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { useKind } from '#ving/record/utils.mjs'; | ||
import { describeParams, getBody, obtainSessionIfRole } from '#ving/utils/rest.mjs'; | ||
import {defineEventHandler} from 'h3'; | ||
export default defineEventHandler(async (event) => { | ||
const cronjobs = await useKind('CronJob'); | ||
const session = obtainSessionIfRole(event, 'verifiedEmail'); | ||
const cronjob = await cronjobs.createAndVerify(await getBody(event), session); | ||
return cronjob.describe(describeParams(event, session)); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { useKind } from '#ving/record/utils.mjs'; | ||
import { describeParams } from '#ving/utils/rest.mjs'; | ||
import {defineEventHandler} from 'h3'; | ||
export default defineEventHandler(async (event) => { | ||
const cronjobs = await useKind('CronJob'); | ||
return cronjobs.mint().propOptions(describeParams(event), true); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
--- | ||
outline: deep | ||
--- | ||
# CronJob | ||
Run background [jobs](../subsystems/jobs) on a set schedule. | ||
|
||
## Filters | ||
|
||
| Prop | Queryable | Qualifier | Range | | ||
| --- | --- | --- | --- | | ||
| createdAt | No | No | Yes | | ||
| updatedAt | No | No | Yes | | ||
| schedule | No | Yes | No | | ||
| handler | No | Yes | No | | ||
|
||
## Endpoints | ||
|
||
### List | ||
|
||
``` | ||
GET /api/v1/cronjob | ||
``` | ||
|
||
### Create | ||
``` | ||
POST /api/v1/cronjob | ||
``` | ||
|
||
### Read | ||
``` | ||
GET /api/v1/cronjob/:id | ||
``` | ||
|
||
### Update | ||
``` | ||
PUT /api/v1/cronjob/:id | ||
``` | ||
|
||
### Delete | ||
``` | ||
DELETE /api/v1/cronjob/:id | ||
``` | ||
|
||
### Options | ||
``` | ||
GET /api/v1/cronjob/options | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { boolean, mysqlEnum, mysqlTable, timestamp, datetime, uniqueIndex, unique, char, varchar, text, int, bigint, json, mediumText, foreignKey } from '#ving/drizzle/orm.mjs'; | ||
|
||
|
||
|
||
export const CronJobTable = mysqlTable('cronjobs', | ||
{ | ||
id: bigint('id', {mode:'number', unsigned: true}).notNull().autoincrement().primaryKey(), | ||
createdAt: timestamp('createdAt').defaultNow().notNull(), | ||
updatedAt: timestamp('updatedAt').defaultNow().notNull().onUpdateNow(), | ||
schedule: varchar('schedule', { length: 60 }).notNull().default('* * * * *'), | ||
handler: varchar('handler', { length: 60 }).notNull().default('Test'), | ||
params: json('params').notNull().default({}), | ||
enabled: boolean('enabled').notNull().default(true), | ||
note: text('note').notNull() | ||
}, | ||
(table) => ({ | ||
|
||
}) | ||
); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import ving from '#ving/index.mjs'; | ||
import { getJobsForHandler, killJob } from "#ving/jobs/queue.mjs"; | ||
|
||
/** | ||
* This handler executes all cron jobs at the same schedule in the CronJob VingRecord. | ||
* @param {Object} A `BullMQ` job. | ||
* @returns {boolean} `true` | ||
*/ | ||
export default async function (job) { | ||
ving.log('jobs').info(`Running CronJobs at schedule ${JSON.stringify(job.data.schedule)}`); | ||
const cronJobs = await ving.useKind('CronJob'); | ||
const records = await cronJobs.findMany({ schedule: job.data.schedule }); | ||
if (records.length == 0) { | ||
ving.log('jobs').info(`No CronJobs found at schedule ${JSON.stringify(job.data.schedule)}. Removing schedule.`); | ||
const jobs = await getJobsForHandler('CronJob'); | ||
for (const rjob of jobs) { | ||
if (job.data.schedule == rjob.data.schedule) | ||
await killJob(rjob.id); | ||
} | ||
} | ||
else { | ||
for (const record of records) { | ||
await record.queueJob(); | ||
} | ||
} | ||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { VingRecord, VingKind, enum2options } from "#ving/record/VingRecord.mjs"; | ||
import { getHandlerNames, addJob } from "#ving/jobs/queue.mjs"; | ||
|
||
/** Management of individual CronJobs. This is needed, because BullMQ won't allow multiple jobs with the | ||
* same schedule to run as cron jobs. So this will execute the `CronJob` handler, which will in turn execute | ||
* any number of cron jobs at that same schedule. This also gives a nice administrative UI for managing | ||
* cron jobs. | ||
* @class | ||
*/ | ||
export class CronJobRecord extends VingRecord { | ||
// add custom Record code here | ||
|
||
/** | ||
* Used with the VingSchema to generate the options for the job handler name. | ||
* @returns {Array} An array of options for the job handler names | ||
* @example | ||
* const options = await cronJob.handlerOptions() | ||
*/ | ||
async handlerOptions() { | ||
const handlerNames = getHandlerNames(); | ||
const filteredHandlerNames = handlerNames.filter((h) => h != 'CronJob'); | ||
return enum2options(filteredHandlerNames, filteredHandlerNames); | ||
} | ||
|
||
/** | ||
* Inserts the current record into the database then adds a BullMQ job to execute the `CronJob` handler. | ||
* @example | ||
* await cronJob.insert() | ||
*/ | ||
async insert() { | ||
await super.insert(); | ||
await addJob('CronJob', { schedule: this.get('schedule') }, { cron: this.get('schedule') }); | ||
} | ||
|
||
/** | ||
* Updates the current record in the database then adds a BullMQ job to execute the `CronJob` handler. | ||
* @example | ||
* await cronJob.update() | ||
*/ | ||
async update() { | ||
await super.update(); | ||
await addJob('CronJob', { schedule: this.get('schedule') }, { cron: this.get('schedule') }); | ||
} | ||
|
||
// don't need a delete, because the `CronJob` handler will delete the job when it is done if there are no | ||
// scheduled jobs with that schedule. | ||
|
||
/** | ||
* Queues a job for this record. | ||
* @example | ||
* await cronJob.queueJob() | ||
*/ | ||
async queueJob() { | ||
if (this.get('enabled') == true) | ||
await addJob(this.get('handler'), this.get('params')); | ||
} | ||
} | ||
|
||
/** Management of all CronJobs. | ||
* @class | ||
*/ | ||
export class CronJobKind extends VingKind { | ||
// add custom Kind code here | ||
|
||
|
||
} |
Oops, something went wrong.