EdgeAIG's picture
download
raw
4.26 kB
/**
* Runs recurring cron jobs through cluster sharding.
*
* This module turns a `Cron.Cron` schedule into a `Layer` that coordinates one
* recurring job across a cluster. It registers a singleton for the initial
* scheduling step and a persisted entity message for each run. This is useful
* for distributed maintenance work where the job should be owned by the cluster
* rather than by every runner independently.
*
* @since 4.0.0
*/
import * as Cron from "../../Cron.js";
import * as DateTime from "../../DateTime.js";
import * as Duration from "../../Duration.js";
import * as Effect from "../../Effect.js";
import * as Exit from "../../Exit.js";
import * as Layer from "../../Layer.js";
import * as Option from "../../Option.js";
import * as PrimaryKey from "../../PrimaryKey.js";
import * as Schedule from "../../Schedule.js";
import * as Schema from "../../Schema.js";
import * as Rpc from "../rpc/Rpc.js";
import * as ClusterSchema from "./ClusterSchema.js";
import { Persisted, Uninterruptible } from "./ClusterSchema.js";
import * as DeliverAt from "./DeliverAt.js";
import * as Entity from "./Entity.js";
import * as Singleton from "./Singleton.js";
/**
* Creates a layer that runs a cron job through the cluster sharding system.
*
* **Details**
*
* The job is scheduled as persisted entity messages, with an initial singleton
* scheduling step and optional controls for shard group, next-run calculation,
* and skipping stale scheduled runs.
*
* @category constructors
* @since 4.0.0
*/
export const make = options => {
const CronEntity = Entity.make(`ClusterCron/${options.name}`, [Rpc.make("run", {
payload: CronPayload
}).annotate(Persisted, true).annotate(Uninterruptible, true)]).annotate(ClusterSchema.ShardGroup, () => options.shardGroup ?? "default").annotate(ClusterSchema.ClientTracingEnabled, false);
const InitialRun = Singleton.make(`ClusterCron/${options.name}`, Effect.gen(function* () {
const now = yield* DateTime.now;
const next = DateTime.fromDateUnsafe(Cron.next(options.cron, now));
const entityId = options.calculateNextRunFromPrevious ? "initial" : DateTime.formatIso(next);
const client = (yield* CronEntity.client)(entityId);
yield* client.run({
dateTime: next
}, {
discard: true
});
}), {
shardGroup: options.shardGroup
});
const skipIfOlderThan = Option.fromUndefinedOr(options.skipIfOlderThan).pipe(Option.map(Duration.fromInputUnsafe), Option.getOrElse(() => Duration.days(1)));
const effect = Effect.fnUntraced(function* (dateTime) {
const now = yield* DateTime.now;
if (DateTime.isLessThan(dateTime, DateTime.subtractDuration(now, skipIfOlderThan))) {
return;
}
return yield* options.execute;
}, Effect.orDie);
const EntityLayer = CronEntity.toLayer(Effect.gen(function* () {
const makeClient = yield* CronEntity.client;
return {
run: request => Effect.onExitPrimitive(effect(request.payload.dateTime), Effect.fnUntraced(function* (exit) {
if (Exit.isFailure(exit)) {
yield* Effect.logWarning(exit.cause);
}
const now = yield* DateTime.now;
const next = DateTime.fromDateUnsafe(Cron.next(options.cron, options.calculateNextRunFromPrevious ? request.payload.dateTime : now));
const client = makeClient(DateTime.formatIso(next));
return yield* client.run({
dateTime: next
}, {
discard: true
}).pipe(Effect.tapCause(cause => Effect.logWarning("Failed to schedule next run, retrying", cause)), Effect.sandbox, Effect.retry(retryPolicy), Effect.orDie);
}), true).pipe(Effect.annotateLogs({
module: "effect/cluster/ClusterCron",
name: options.name,
dateTime: request.payload.dateTime
}))
};
}));
return Layer.merge(InitialRun, EntityLayer);
};
const retryPolicy = /*#__PURE__*/Schedule.exponential(200, 1.5).pipe(/*#__PURE__*/Schedule.either(/*#__PURE__*/Schedule.spaced("1 minute")));
class CronPayload extends /*#__PURE__*/Schema.Class("effect/cluster/ClusterCron/CronPayload")({
dateTime: Schema.DateTimeUtc
}) {
[PrimaryKey.symbol]() {
return "";
}
[DeliverAt.symbol]() {
return this.dateTime;
}
}
//# sourceMappingURL=ClusterCron.js.map

Xet Storage Details

Size:
4.26 kB
·
Xet hash:
471baa583f1cecbf999500a46dbe19e19843a2281b4822ca1a957f48f5e4862f

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.