Skip to content

Add websocket idle timeout metric (#5358) #2296

Add websocket idle timeout metric (#5358)

Add websocket idle timeout metric (#5358) #2296

Workflow file for this run

name: Discord notifications
on:
push:
branches:
- master
permissions:
contents: read
pull-requests: read
jobs:
resolvePush:
runs-on: ubuntu-latest
outputs:
is_pr_merge: ${{ steps.resolve.outputs.is_pr_merge }}
is_external: ${{ steps.resolve.outputs.is_external }}
pr_author: ${{ steps.resolve.outputs.pr_author }}
pr_head_ref: ${{ steps.resolve.outputs.pr_head_ref }}
pr_head_repo: ${{ steps.resolve.outputs.pr_head_repo }}
pr_number: ${{ steps.resolve.outputs.pr_number }}
pr_title: ${{ steps.resolve.outputs.pr_title }}
pr_url: ${{ steps.resolve.outputs.pr_url }}
steps:
- name: Resolve pushed commit
id: resolve
uses: actions/github-script@v7
with:
script: |
const { owner, repo } = context.repo;
const sha = context.sha;
async function findAssociatedPRs() {
// It seems that when we do this too promptly after a PR merge then the data isn't there, so we have a retry loop.
for (let attempt = 1; attempt <= 3; attempt++) {
core.info('Looking for associated PRs..');
const prs = await github.paginate(github.rest.repos.listPullRequestsAssociatedWithCommit, {
owner,
repo,
commit_sha: sha,
});
if (prs.length > 0) {
return prs;
}
core.info('No associated PRs found. Will check again.');
await new Promise((resolve) => setTimeout(resolve, 30000));
}
return [];
}
const prs = await findAssociatedPRs();
core.info(`Associated PR info found:`);
core.info(JSON.stringify(prs, null, 2));
if (prs.length === 0) {
core.info('No associated PRs found. Treating this push as a direct/non-PR push.');
core.setOutput('is_pr_merge', 'false');
core.info('Output is_pr_merge=false');
return;
}
if (prs.length > 1) {
core.info('Multiple associated PRs found. Failing because downstream notification expects exactly one PR.');
core.setFailed(`Expected exactly one PR associated with ${sha}, found ${prs.length}.`);
return;
}
const pr = prs[0];
const headRepo = pr.head?.repo?.full_name || '';
core.setOutput('is_pr_merge', 'true');
core.setOutput('is_external', String(headRepo !== `${owner}/${repo}`));
core.setOutput('pr_author', pr.user?.login || '');
core.setOutput('pr_head_ref', pr.head?.ref || '');
core.setOutput('pr_head_repo', headRepo);
core.setOutput('pr_number', String(pr.number));
core.setOutput('pr_title', pr.title || '');
core.setOutput('pr_url', pr.html_url || '');
discordNotification:
needs: resolvePush
runs-on: ubuntu-latest
if: needs.resolvePush.outputs.is_pr_merge == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Set up GitHub CLI
run: |
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /usr/share/keyrings/githubcli-archive-keyring.gpg > /dev/null
sudo apt-get install -y apt-transport-https
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list
sudo apt-get update
sudo apt-get install -y gh
# TODO: Perhaps we should merge this into the public-pr-merge.yml workflow, now that that exists.
- name: Send Discord notification
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
PR_AUTHOR: ${{ needs.resolvePush.outputs.pr_author }}
PR_HEAD_REF: ${{ needs.resolvePush.outputs.pr_head_ref }}
PR_HEAD_REPO: ${{ needs.resolvePush.outputs.pr_head_repo }}
PR_IS_EXTERNAL: ${{ needs.resolvePush.outputs.is_external }}
PR_TITLE: ${{ needs.resolvePush.outputs.pr_title }}
PR_NUMBER: ${{ needs.resolvePush.outputs.pr_number }}
PR_URL: ${{ needs.resolvePush.outputs.pr_url }}
MENTION_ON_FAILURE: ${{ secrets.DEV_OPS_ROLE_ID }}
DISCORD_USER_MAP: ${{ secrets.DISCORD_USER_MAP }}
run: |
message="PR merged: [(#${PR_NUMBER}) ${PR_TITLE}](<${PR_URL}>)"
if [[ "${PR_IS_EXTERNAL}" == "true" ]]; then
message+=$'\n'
message+="External PR source: ${PR_HEAD_REPO}@${PR_HEAD_REF}"
fi
# Note that anything besides success is treated as a failure (e.g. if the check did not run at all, or if it is still pending).
FAILED_CHECKS="$(
gh pr checks "${PR_URL}" \
--json 'workflow,state,name' |
jq '.[]
| select(.workflow != "Discord notifications")
| select(.state != "SUCCESS" and .state != "NEUTRAL" and .state != "SKIPPED")
' |
jq -r '"\(.workflow) / \(.name): \(.state)"'
)"
# Lookup PR author's Discord ID from the provided JSON map (if any)
author_discord_id="$(
jq -r \
--arg u "${PR_AUTHOR}" \
'.[$u] // empty' \
<<<"${DISCORD_USER_MAP}"
)"
if [ -z "${author_discord_id}" ]; then
echo "Warning: PR author not found not found in USER_LOOKUP_JSON"
fi
message+=$'\n'
if [[ -z "${FAILED_CHECKS}" ]]; then
message+='All checks passed.'
else
message+="${FAILED_CHECKS}"
message+=$'\n'
# This uses special Discord syntax for pinging a particular role.
# Note the '&' - this is the difference between pinging a *role* and pinging a *person*.
if [[ -n "${author_discord_id}" ]]; then
message+="<@${author_discord_id}> please investigate these failures."
fi
message+=$'\n'
message+="(cc <@&${MENTION_ON_FAILURE}> - Releases may be affected)"
fi
# Use `jq` to construct the json data blob in the format required by the webhook.
data="$(jq --null-input --arg msg "$message" '.content=$msg')"
curl -X POST -H 'Content-Type: application/json' -d "$data" "${DISCORD_WEBHOOK_URL}"
notifyFailure:
needs:
- resolvePush
- discordNotification
runs-on: ubuntu-latest
if: ${{ always() && (needs.resolvePush.result == 'failure' || needs.discordNotification.result == 'failure') }}
steps:
- name: Send failure notification
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
run: |
message="Discord notification workflow failed."
message+=$'\n'
message+="Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
data="$(jq --null-input --arg msg "$message" '.content=$msg')"
curl -X POST -H 'Content-Type: application/json' -d "$data" "${DISCORD_WEBHOOK_URL}"
warnDirectPush:
needs: resolvePush
runs-on: ubuntu-latest
if: needs.resolvePush.outputs.is_pr_merge != 'true'
steps:
- name: Warn about non-PR push
env:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
COMMIT_URL: ${{ github.event.head_commit.url }}
PUSHER: ${{ github.event.pusher.name }}
SHA: ${{ github.sha }}
run: |
short_sha="${SHA:0:7}"
subject="$(printf '%s\n' "${COMMIT_MESSAGE}" | head -n 1)"
message="Warning: push to master was not associated with a merged PR."
message+=$'\n'
message+="Commit: [${short_sha}](<${COMMIT_URL}>)"
message+=$'\n'
message+="Pusher: ${PUSHER}"
message+=$'\n'
message+="Subject: ${subject}"
data="$(jq --null-input --arg msg "$message" '.content=$msg')"
curl -X POST -H 'Content-Type: application/json' -d "$data" "${DISCORD_WEBHOOK_URL}"
invokePrivate:
needs: resolvePush
runs-on: ubuntu-latest
if: needs.resolvePush.outputs.is_pr_merge == 'true'
permissions:
contents: read
steps:
- name: Dispatch private merge workflow
uses: actions/github-script@v7
with:
github-token: ${{ secrets.SPACETIMEDB_PRIVATE_TOKEN }}
script: |
await github.rest.actions.createWorkflowDispatch({
owner: 'clockworklabs',
repo: 'SpacetimeDBPrivate',
workflow_id: 'public-pr-merge.yml',
ref: 'master',
inputs: {
public_pr_number: '${{ needs.resolvePush.outputs.pr_number }}',
}
});