Skip to content

Commit

Permalink
chore: improve random cron generation (#411)
Browse files Browse the repository at this point in the history
I noticed the lock workflow was still failing sometimes, and from what I
could tell the runs that failed were most likely to be during business
hours (US time). I'm hoping we can address the issue by running during
the night (early morning hours UTC).

While I was at it, I refactored Mutahhir's great work into a separate
script so that it could be reused across workflows; another one that
makes a fair number of API calls that could benefit from this approach
is the stale workflow.
  • Loading branch information
xiehan authored Apr 5, 2024
1 parent 7b8907d commit 8d8fe3f
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 29 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 12 additions & 2 deletions src/alert-open-prs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { cdk } from "projen";
import { GithubWorkflow } from "projen/lib/github";
import { JobPermission } from "projen/lib/github/workflows-model";
import { generateRandomCron, Schedule } from "./util/random-cron";

const DEFAULT_MAX_HOURS_OPEN = 2;

Expand All @@ -25,8 +26,17 @@ export class AlertOpenPrs {

const workflow = new GithubWorkflow(project.github!, "alert-open-prs");
workflow.on({
workflowDispatch: {},
schedule: [{ cron: "* */12 * * 1-5" }], // every 12 hours, Monday-Friday
// run on weekdays sometime during working hours (8am-4pm UTC)
schedule: [
{
cron: generateRandomCron({
project,
maxHour: 8,
hourOffset: 8,
schedule: Schedule.Weekdays,
}),
},
],
});
workflow.addJob("check-open-prs", {
runsOn: ["ubuntu-latest"],
Expand Down
8 changes: 8 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { PackageInfo } from "./package-info";
import { ProviderUpgrade } from "./provider-upgrade";
import { CheckForUpgradesScriptFile } from "./scripts/check-for-upgrades";
import { ShouldReleaseScriptFile } from "./scripts/should-release";
import { generateRandomCron } from "./util/random-cron";

// ensure new projects start with 1.0.0 so that every following breaking change leads to an increased major version
const MIN_MAJOR_VERSION = 1;
Expand Down Expand Up @@ -450,6 +451,13 @@ export class CdktfProviderProject extends cdk.JsiiProject {
" or cancel via faking a SHA if release was cancelled";
}

const staleWorkflow = this.tryFindObjectFile(".github/workflows/stale.yml");
staleWorkflow?.addOverride("on.schedule", [
{
cron: generateRandomCron({ project: this, maxHour: 4, hourOffset: 1 }),
},
]);

// Submodule documentation generation
this.gitignore.exclude("API.md"); // ignore the old file, we now generate it in the docs folder
this.addDevDeps("jsii-docgen@^10.2.3");
Expand Down
11 changes: 3 additions & 8 deletions src/lock-issues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
* SPDX-License-Identifier: MPL-2.0
*/

import { createHash } from "crypto";
import { javascript } from "projen";
import { JobPermission } from "projen/lib/github/workflows-model";
import { generateRandomCron } from "./util/random-cron";

/**
* Automatically locks issues and PRs after 7 days. Note that 90% of the issues and PRs
Expand All @@ -18,14 +18,9 @@ export class LockIssues {

if (!workflow) throw new Error("no workflow defined");

const projectNameHash = createHash("md5")
.update(project.name)
.digest("hex");
const scheduleHour = parseInt(projectNameHash.slice(0, 2), 16) % 24;
const scheduleMinute = parseInt(projectNameHash.slice(2, 4), 16) % 24;

workflow.on({
schedule: [{ cron: `${scheduleHour} ${scheduleMinute} * * *` }],
// run daily sometime between midnight and 6am UTC
schedule: [{ cron: generateRandomCron({ project, maxHour: 6 }) }],
});

workflow.addJob("lock", {
Expand Down
42 changes: 42 additions & 0 deletions src/util/random-cron.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import { createHash } from "crypto";
import { javascript } from "projen";

export enum Schedule {
Daily = "DAILY",
Weekly = "WEEKLY",
Monthly = "MONTHLY",
Weekdays = "WEEKDAYS",
}

export interface RandomCronOptions {
project: javascript.NodeProject;
maxHour?: number;
hourOffset?: number;
schedule?: Schedule;
}

export function generateRandomCron(options: RandomCronOptions) {
const maxHour = options.maxHour ? Math.round(options.maxHour) : 24;
const hourOffset = options.hourOffset ? Math.round(options.hourOffset) : 0;
const schedule = options.schedule || Schedule.Daily; // default to daily

const project = options.project;
const hash = createHash("md5").update(project.name).digest("hex");
const hour = maxHour === 0 ? 0 : parseInt(hash.slice(0, 2), 16) % maxHour;
const minute = parseInt(hash.slice(2, 4), 16) % 60;

const dayOfMonth = schedule === Schedule.Monthly ? "1" : "*";
const dayOfWeek =
schedule === Schedule.Weekly
? "1"
: schedule === Schedule.Weekdays
? "1-5"
: "*";

return `${minute} ${(hour + hourOffset) % 24} ${dayOfMonth} * ${dayOfWeek}`;
}
32 changes: 14 additions & 18 deletions test/__snapshots__/index.test.ts.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8d8fe3f

Please sign in to comment.