Skip to main content

Automatisches erneutes Zustellen fehlgeschlagener Zustellungen für einen GitHub-App-Webhook

Du kannst ein Skript schreiben, um fehlgeschlagene Zustellungen eines GitHub App-Webhook zu verarbeiten.

Informationen zur automatischen erneuten Zustellung fehlgeschlagener Zustellungen

In diesem Artikel wird beschrieben, wie du ein Skript schreibst, um fehlgeschlagene Zustellungen für einen GitHub App-Webhook zu finden und erneut zu senden. Weitere Informationen zu fehlgeschlagenen Zustellungen findest du unter Bearbeitung fehlgeschlagener Webhook-Zustellungen.

In diesem Beispiel wird Folgendes angezeigt:

  • Ein Skript, das fehlgeschlagene Zustellungen für einen GitHub App-Webhook findet und erneut sendet
  • Welche Anmeldeinformationen für dein Skript erforderlich sind und wie du sie sicher als GitHub Actions-Geheimnisse speichern kannst
  • Ein GitHub Actions-Workflow, der sicher auf deine Anmeldeinformationen zugreifen und das Skript regelmäßig ausführen kann

In diesem Beispiel werden GitHub Actions verwendet. Du kannst dieses Skript aber auch auf deinem Server ausführen, der Webhookübermittlungen verarbeitet. Weitere Informationen findest du unter Alternative Methoden.

Speichern von Anmeldeinformationen für das Skript

Für die Endpunkte ist zum Auffinden und erneuten Senden fehlgeschlagener Webhooks ein JSON-Webtoken erforderlich, das aus der App-ID und dem privaten Schlüssel für deine App generiert wird.

Für die Endpunkte ist zum Abrufen und Aktualisieren des Werts von Umgebungsvariablen ein personal access token, GitHub App-Installationszugriffstoken oder GitHub App-Benutzerzugriffstoken erforderlich. In diesem Beispiel wird ein personal access token verwendet. Wenn dein GitHub App im Repository installiert ist, in dem dieser Workflow ausgeführt wird und der über die Berechtigung zum Schreiben von Repositoryvariablen verfügt, kannst du dieses Beispiel ändern, um ein Installationszugriffstoken während des GitHub Actions-Workflows zu erstellen, anstatt einen personal access token zu verwenden. Weitere Informationen findest du unter Authentifizierte API-Anforderungen mit einer GitHub-App in einem GitHub Actions-Workflow.

  1. Suche die App-ID für deine GitHub App. Du findest die App-ID auf der Einstellungsseite deiner App. Die App-ID unterscheidet sich von der Client-ID. Weitere Informationen zum Aufrufen der Einstellungsseite für deine GitHub App findest du unter Ändern einer GitHub-App-Registrierung.

  2. Speichere die App-ID aus dem vorherigen Schritt als GitHub Actions-Geheimnis im Repository, in dem der Workflow ausgeführt werden soll. Weitere Informationen zum Speichern von Geheimnissen findest du unter Verwenden von Geheimnissen in GitHub-Aktionen.

  3. Generiere einen privaten Schlüssel für deine App. Weitere Informationen zum Generieren eines privaten Schlüssels findest du unter Verwalten privater Schlüssel für GitHub-Apps.

  4. Speichere den privaten Schlüssel, einschließlich -----BEGIN RSA PRIVATE KEY----- und -----END RSA PRIVATE KEY-----, aus dem vorherigen Schritt als GitHub Actions-Geheimnis im Repository, in dem der Workflow ausgeführt werden soll.

  5. Erstellen Sie eine personal access token mit dem folgenden Zugriff: Weitere Informationen findest du unter Verwalten deiner persönlichen Zugriffstoken.

    • Für eine fine-grained personal access token, weisen Sie folgendes Token zu:
      • Schreibzugriff auf die Repositoryvariablen-Berechtigung
      • Zugriff auf das Repository, in dem dieser Workflow ausgeführt wird
    • Für eine personal access token (classic), weisen Sie dem Token den repo-Reservierungsumfang zu:
  6. Speichere deine personal access token aus dem vorherigen Schritt als GitHub Actions-Geheimnis in dem Repository, in dem der Workflow ausgeführt werden soll.

Hinzufügen eines Workflows, der das Skript ausführt

In diesem Abschnitt wird veranschaulicht, wie du einen GitHub Actions-Workflow verwenden kannst, um sicher auf die Anmeldeinformationen zuzugreifen, die du im vorherigen Abschnitt gespeichert hast, und um Umgebungsvariablen festzulegen und regelmäßig ein Skript auszuführen, um fehlgeschlagene Zustellungen zu finden und erneut zu senden.

Kopieren Sie diesen GitHub Actions Workflow in eine YAML-Datei in das .github/workflows-Verzeichnis des Repositorys, in dem der Workflow ausgeführt werden soll. Ersetzen Sie die Platzhalter im Run script-Schritt wie unten beschrieben.

YAML
name: Redeliver failed webhook deliveries
on:
  schedule:
    - cron: '40 */6 * * *'
  workflow_dispatch:

This workflow runs every 6 hours or when manually triggered.

permissions:
  contents: read

This workflow will use the built in GITHUB_TOKEN to check out the repository contents. This grants GITHUB_TOKEN permission to do that.

jobs:
  redeliver-failed-deliveries:
    name: Redeliver failed deliveries
    runs-on: ubuntu-latest
    steps:
      - name: Check out repo content
        uses: actions/checkout@v4

This workflow will run a script that is stored in the repository. This step checks out the repository contents so that the workflow can access the script.

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18.x'

This step sets up Node.js. The script that this workflow will run uses Node.js.

      - name: Install dependencies
        run: npm install octokit

This step installs the octokit library. The script that this workflow will run uses the octokit library.

      - name: Run script
        env:
          APP_ID: ${{ secrets.YOUR_APP_ID_SECRET_NAME }}
          PRIVATE_KEY: ${{ secrets.YOUR_PRIVATE_KEY_SECRET_NAME }}
          TOKEN: ${{ secrets.YOUR_TOKEN_SECRET_NAME }}
          LAST_REDELIVERY_VARIABLE_NAME: 'YOUR_LAST_REDELIVERY_VARIABLE_NAME'
          HOSTNAME: 'YOUR_HOSTNAME'
          WORKFLOW_REPO: ${{ github.event.repository.name }}
          WORKFLOW_REPO_OWNER: ${{ github.repository_owner }}
        run: |
          node .github/workflows/scripts/redeliver-failed-deliveries.js

This step sets some environment variables, then runs a script to find and redeliver failed webhook deliveries.

  • Replace YOUR_APP_ID_SECRET_NAME with the name of the secret where you stored your app ID.
  • Replace YOUR_PRIVATE_KEY_SECRET_NAME with the name of the secret where you stored your private key.
  • Replace YOUR_TOKEN_SECRET_NAME with the name of the secret where you stored your personal access token.
  • Replace YOUR_LAST_REDELIVERY_VARIABLE_NAME with the name that you want to use for a configuration variable that will be stored in the repository where this workflow is stored. The name can be any string that contains only alphanumeric characters and _, and does not start with GITHUB_ or a number. For more information, see "Speichern von Informationen in Variablen."
  • Replace YOUR_HOSTNAME with the name of Ihre GitHub Enterprise Server-Instance.
#
name: Redeliver failed webhook deliveries

# This workflow runs every 6 hours or when manually triggered.
on:
  schedule:
    - cron: '40 */6 * * *'
  workflow_dispatch:

# This workflow will use the built in `GITHUB_TOKEN` to check out the repository contents. This grants `GITHUB_TOKEN` permission to do that.
permissions:
  contents: read

#
jobs:
  redeliver-failed-deliveries:
    name: Redeliver failed deliveries
    runs-on: ubuntu-latest
    steps:
      # This workflow will run a script that is stored in the repository. This step checks out the repository contents so that the workflow can access the script.
      - name: Check out repo content
        uses: actions/checkout@v4

      # This step sets up Node.js. The script that this workflow will run uses Node.js.
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18.x'

      # This step installs the octokit library. The script that this workflow will run uses the octokit library.
      - name: Install dependencies
        run: npm install octokit

      # This step sets some environment variables, then runs a script to find and redeliver failed webhook deliveries.
      # - Replace `YOUR_APP_ID_SECRET_NAME` with the name of the secret where you stored your app ID.
      # - Replace `YOUR_PRIVATE_KEY_SECRET_NAME` with the name of the secret where you stored your private key.
      # - Replace `YOUR_TOKEN_SECRET_NAME` with the name of the secret where you stored your personal access token.
      # - Replace `YOUR_LAST_REDELIVERY_VARIABLE_NAME` with the name that you want to use for a configuration variable that will be stored in the repository where this workflow is stored. The name can be any string that contains only alphanumeric characters and `_`, and does not start with `GITHUB_` or a number. For more information, see "[AUTOTITLE](/actions/learn-github-actions/variables#defining-configuration-variables-for-multiple-workflows)."
      # - Replace `YOUR_HOSTNAME` with the name of Ihre GitHub Enterprise Server-Instance.
      - name: Run script
        env:
          APP_ID: ${{ secrets.YOUR_APP_ID_SECRET_NAME }}
          PRIVATE_KEY: ${{ secrets.YOUR_PRIVATE_KEY_SECRET_NAME }}
          TOKEN: ${{ secrets.YOUR_TOKEN_SECRET_NAME }}
          LAST_REDELIVERY_VARIABLE_NAME: 'YOUR_LAST_REDELIVERY_VARIABLE_NAME'
          HOSTNAME: 'YOUR_HOSTNAME'
          WORKFLOW_REPO: ${{ github.event.repository.name }}
          WORKFLOW_REPO_OWNER: ${{ github.repository_owner }}
        run: |
          node .github/workflows/scripts/redeliver-failed-deliveries.js

Hinzufügen des Skripts

In diesem Abschnitt wird veranschaulicht, wie du ein Skript schreiben kannst, um fehlgeschlagene Zustellungen zu finden und erneut zu senden.

Kopieren Sie dieses Skript in eine Datei mit dem Namen .github/workflows/scripts/redeliver-failed-deliveries.js, die in demselben Repository aufgerufen wird, in dem Sie oben die GitHub Actions-Workflow-Datei gespeichert haben.

JavaScript
const { App, Octokit } = require("octokit");

This script uses GitHub's Octokit SDK to make API requests. For more information, see "Skripterstellung mit der REST-API und JavaScript."

async function checkAndRedeliverWebhooks() {
  const APP_ID = process.env.APP_ID;
  const PRIVATE_KEY = process.env.PRIVATE_KEY;
  const TOKEN = process.env.TOKEN;
  const LAST_REDELIVERY_VARIABLE_NAME = process.env.LAST_REDELIVERY_VARIABLE_NAME;
  const HOSTNAME = process.env.HOSTNAME;
  const WORKFLOW_REPO_NAME = process.env.WORKFLOW_REPO;
  const WORKFLOW_REPO_OWNER = process.env.WORKFLOW_REPO_OWNER;

Get the values of environment variables that were set by the GitHub Actions workflow.

  const app = new App({
    appId: APP_ID,
    privateKey: PRIVATE_KEY,
    Octokit: Octokit.defaults({
      baseUrl: "http(s)://HOSTNAME/api/v3",
    }),
  });

Create an instance of the octokit App using the app ID, private key, and hostname values that were set in the GitHub Actions workflow.

This will be used to make API requests to the webhook-related endpoints.

  const octokit = new Octokit({ 
    baseUrl: "http(s)://HOSTNAME/api/v3",
    auth: TOKEN,
  });
  try {

Create an instance of Octokit using the token and hostname values that were set in the GitHub Actions workflow.

This will be used to update the configuration variable that stores the last time that this script ran.

    const lastStoredRedeliveryTime = await getVariable({
      variableName: LAST_REDELIVERY_VARIABLE_NAME,
      repoOwner: WORKFLOW_REPO_OWNER,
      repoName: WORKFLOW_REPO_NAME,
      octokit,
    });
    const lastWebhookRedeliveryTime = lastStoredRedeliveryTime || (Date.now() - (24 * 60 * 60 * 1000)).toString();

Get the last time that this script ran from the configuration variable. If the variable is not defined, use the current time minus 24 hours.

    const newWebhookRedeliveryTime = Date.now().toString();

Record the time that this script started redelivering webhooks.

    const deliveries = await fetchWebhookDeliveriesSince({lastWebhookRedeliveryTime, app});

Get the webhook deliveries that were delivered after lastWebhookRedeliveryTime.

    let deliveriesByGuid = {};
    for (const delivery of deliveries) {
      deliveriesByGuid[delivery.guid]
        ? deliveriesByGuid[delivery.guid].push(delivery)
        : (deliveriesByGuid[delivery.guid] = [delivery]);
    }

Consolidate deliveries that have the same globally unique identifier (GUID). The GUID is constant across redeliveries of the same delivery.

    let failedDeliveryIDs = [];
    for (const guid in deliveriesByGuid) {
      const deliveries = deliveriesByGuid[guid];
      const anySucceeded = deliveries.some(
        (delivery) => delivery.status === "OK"
      );
      if (!anySucceeded) {
        failedDeliveryIDs.push(deliveries[0].id);
      }
    }

For each GUID value, if no deliveries for that GUID have been successfully delivered within the time frame, get the delivery ID of one of the deliveries with that GUID.

This will prevent duplicate redeliveries if a delivery has failed multiple times. This will also prevent redelivery of failed deliveries that have already been successfully redelivered.

    for (const deliveryId of failedDeliveryIDs) {
      await redeliverWebhook({deliveryId, app});
    }

Redeliver any failed deliveries.

    await updateVariable({
      variableName: LAST_REDELIVERY_VARIABLE_NAME,
      value: newWebhookRedeliveryTime,
      variableExists: Boolean(lastStoredRedeliveryTime),
      repoOwner: WORKFLOW_REPO_OWNER,
      repoName: WORKFLOW_REPO_NAME,
      octokit,
      });

Update the configuration variable (or create the variable if it doesn't already exist) to store the time that this script started. This value will be used next time this script runs.

    console.log(
      `Redelivered ${
        failedDeliveryIDs.length
      } failed webhook deliveries out of ${
        deliveries.length
      } total deliveries since ${Date(lastWebhookRedeliveryTime)}.`
    );
  } catch (error) {

Log the number of redeliveries.

    if (error.response) {
      console.error(
        `Failed to check and redeliver webhooks: ${error.response.data.message}`
      );
    }
    console.error(error);
    throw(error);
  }
}

If there was an error, log the error so that it appears in the workflow run log, then throw the error so that the workflow run registers as a failure.

async function fetchWebhookDeliveriesSince({lastWebhookRedeliveryTime, app}) {
  const iterator = app.octokit.paginate.iterator(
    "GET /app/hook/deliveries",
    {
      per_page: 100,
      headers: {
        "x-github-api-version": "2022-11-28",
      },
    }
  );
  const deliveries = [];
  for await (const { data } of iterator) {
    const oldestDeliveryTimestamp = new Date(
      data[data.length - 1].delivered_at
    ).getTime();
    if (oldestDeliveryTimestamp < lastWebhookRedeliveryTime) {
      for (const delivery of data) {
        if (
          new Date(delivery.delivered_at).getTime() > lastWebhookRedeliveryTime
        ) {
          deliveries.push(delivery);
        } else {
          break;
        }
      }
      break;
    } else {
      deliveries.push(...data);
    }
  }
  return deliveries;
}

This function will fetch all of the webhook deliveries that were delivered since lastWebhookRedeliveryTime. It uses the octokit.paginate.iterator() method to iterate through paginated results. For more information, see "Skripterstellung mit der REST-API und JavaScript."

If a page of results includes deliveries that occurred before lastWebhookRedeliveryTime, it will store only the deliveries that occurred after lastWebhookRedeliveryTime and then stop. Otherwise, it will store all of the deliveries from the page and request the next page.

async function redeliverWebhook({deliveryId, app}) {
  await app.octokit.request("POST /app/hook/deliveries/{delivery_id}/attempts", {
    delivery_id: deliveryId,
  });
}

This function will redeliver a failed webhook delivery.

async function getVariable({ variableName, repoOwner, repoName, octokit }) {
  try {
    const {
      data: { value },
    } = await octokit.request(
      "GET /repos/{owner}/{repo}/actions/variables/{name}",
      {
        owner: repoOwner,
        repo: repoName,
        name: variableName,
      }
    );
    return value;
  } catch (error) {
    if (error.status === 404) {
      return undefined;
    } else {
      throw error;
    }
  }
}

This function gets the value of a configuration variable. If the variable does not exist, the endpoint returns a 404 response and this function returns undefined.

async function updateVariable({
  variableName,
  value,
  variableExists,
  repoOwner,
  repoName,
  octokit,
}) {
  if (variableExists) {
    await octokit.request(
      "PATCH /repos/{owner}/{repo}/actions/variables/{name}",
      {
        owner: repoOwner,
        repo: repoName,
        name: variableName,
        value: value,
      }
    );
  } else {
    await octokit.request("POST /repos/{owner}/{repo}/actions/variables", {
      owner: repoOwner,
      repo: repoName,
      name: variableName,
      value: value,
    });
  }
}

This function will update a configuration variable (or create the variable if it doesn't already exist). For more information, see "Speichern von Informationen in Variablen."

(async () => {
  await checkAndRedeliverWebhooks();
})();

This will execute the checkAndRedeliverWebhooks function.

// This script uses GitHub's Octokit SDK to make API requests. For more information, see "[AUTOTITLE](/rest/guides/scripting-with-the-rest-api-and-javascript)."
const { App, Octokit } = require("octokit");

//
async function checkAndRedeliverWebhooks() {
  // Get the values of environment variables that were set by the GitHub Actions workflow.
  const APP_ID = process.env.APP_ID;
  const PRIVATE_KEY = process.env.PRIVATE_KEY;
  const TOKEN = process.env.TOKEN;
  const LAST_REDELIVERY_VARIABLE_NAME = process.env.LAST_REDELIVERY_VARIABLE_NAME;
  const HOSTNAME = process.env.HOSTNAME;
  const WORKFLOW_REPO_NAME = process.env.WORKFLOW_REPO;
  const WORKFLOW_REPO_OWNER = process.env.WORKFLOW_REPO_OWNER;

  // Create an instance of the octokit `App` using the app ID, private key, and hostname values that were set in the GitHub Actions workflow.
  //
  // This will be used to make API requests to the webhook-related endpoints.
  const app = new App({
    appId: APP_ID,
    privateKey: PRIVATE_KEY,
    Octokit: Octokit.defaults({
      baseUrl: "http(s)://HOSTNAME/api/v3",
    }),
  });

  // Create an instance of `Octokit` using the token and hostname values that were set in the GitHub Actions workflow.
  //
  // This will be used to update the configuration variable that stores the last time that this script ran.
  const octokit = new Octokit({ 
    baseUrl: "http(s)://HOSTNAME/api/v3",
    auth: TOKEN,
  });

  try {
    // Get the last time that this script ran from the configuration variable. If the variable is not defined, use the current time minus 24 hours.
    const lastStoredRedeliveryTime = await getVariable({
      variableName: LAST_REDELIVERY_VARIABLE_NAME,
      repoOwner: WORKFLOW_REPO_OWNER,
      repoName: WORKFLOW_REPO_NAME,
      octokit,
    });
    const lastWebhookRedeliveryTime = lastStoredRedeliveryTime || (Date.now() - (24 * 60 * 60 * 1000)).toString();

    // Record the time that this script started redelivering webhooks.
    const newWebhookRedeliveryTime = Date.now().toString();

    // Get the webhook deliveries that were delivered after `lastWebhookRedeliveryTime`.
    const deliveries = await fetchWebhookDeliveriesSince({lastWebhookRedeliveryTime, app});

    // Consolidate deliveries that have the same globally unique identifier (GUID). The GUID is constant across redeliveries of the same delivery.
    let deliveriesByGuid = {};
    for (const delivery of deliveries) {
      deliveriesByGuid[delivery.guid]
        ? deliveriesByGuid[delivery.guid].push(delivery)
        : (deliveriesByGuid[delivery.guid] = [delivery]);
    }

    // For each GUID value, if no deliveries for that GUID have been successfully delivered within the time frame, get the delivery ID of one of the deliveries with that GUID.
    //
    // This will prevent duplicate redeliveries if a delivery has failed multiple times.
    // This will also prevent redelivery of failed deliveries that have already been successfully redelivered.
    let failedDeliveryIDs = [];
    for (const guid in deliveriesByGuid) {
      const deliveries = deliveriesByGuid[guid];
      const anySucceeded = deliveries.some(
        (delivery) => delivery.status === "OK"
      );
      if (!anySucceeded) {
        failedDeliveryIDs.push(deliveries[0].id);
      }
    }

    // Redeliver any failed deliveries.
    for (const deliveryId of failedDeliveryIDs) {
      await redeliverWebhook({deliveryId, app});
    }

    // Update the configuration variable (or create the variable if it doesn't already exist) to store the time that this script started.
    // This value will be used next time this script runs.
    await updateVariable({
      variableName: LAST_REDELIVERY_VARIABLE_NAME,
      value: newWebhookRedeliveryTime,
      variableExists: Boolean(lastStoredRedeliveryTime),
      repoOwner: WORKFLOW_REPO_OWNER,
      repoName: WORKFLOW_REPO_NAME,
      octokit,
      });

    // Log the number of redeliveries.
    console.log(
      `Redelivered ${
        failedDeliveryIDs.length
      } failed webhook deliveries out of ${
        deliveries.length
      } total deliveries since ${Date(lastWebhookRedeliveryTime)}.`
    );
  } catch (error) {
    // If there was an error, log the error so that it appears in the workflow run log, then throw the error so that the workflow run registers as a failure.
    if (error.response) {
      console.error(
        `Failed to check and redeliver webhooks: ${error.response.data.message}`
      );
    }
    console.error(error);
    throw(error);
  }
}

// This function will fetch all of the webhook deliveries that were delivered since `lastWebhookRedeliveryTime`.
// It uses the `octokit.paginate.iterator()` method to iterate through paginated results. For more information, see "[AUTOTITLE](/rest/guides/scripting-with-the-rest-api-and-javascript#making-paginated-requests)."
//
// If a page of results includes deliveries that occurred before `lastWebhookRedeliveryTime`,
// it will store only the deliveries that occurred after `lastWebhookRedeliveryTime` and then stop.
// Otherwise, it will store all of the deliveries from the page and request the next page.
async function fetchWebhookDeliveriesSince({lastWebhookRedeliveryTime, app}) {
  const iterator = app.octokit.paginate.iterator(
    "GET /app/hook/deliveries",
    {
      per_page: 100,
      headers: {
        "x-github-api-version": "2022-11-28",
      },
    }
  );

  const deliveries = [];

  for await (const { data } of iterator) {
    const oldestDeliveryTimestamp = new Date(
      data[data.length - 1].delivered_at
    ).getTime();

    if (oldestDeliveryTimestamp < lastWebhookRedeliveryTime) {
      for (const delivery of data) {
        if (
          new Date(delivery.delivered_at).getTime() > lastWebhookRedeliveryTime
        ) {
          deliveries.push(delivery);
        } else {
          break;
        }
      }
      break;
    } else {
      deliveries.push(...data);
    }
  }

  return deliveries;
}

// This function will redeliver a failed webhook delivery.
async function redeliverWebhook({deliveryId, app}) {
  await app.octokit.request("POST /app/hook/deliveries/{delivery_id}/attempts", {
    delivery_id: deliveryId,
  });
}

// This function gets the value of a configuration variable.
// If the variable does not exist, the endpoint returns a 404 response and this function returns `undefined`.
async function getVariable({ variableName, repoOwner, repoName, octokit }) {
  try {
    const {
      data: { value },
    } = await octokit.request(
      "GET /repos/{owner}/{repo}/actions/variables/{name}",
      {
        owner: repoOwner,
        repo: repoName,
        name: variableName,
      }
    );
    return value;
  } catch (error) {
    if (error.status === 404) {
      return undefined;
    } else {
      throw error;
    }
  }
}

// This function will update a configuration variable (or create the variable if it doesn't already exist). For more information, see "[AUTOTITLE](/actions/learn-github-actions/variables#defining-configuration-variables-for-multiple-workflows)."
async function updateVariable({
  variableName,
  value,
  variableExists,
  repoOwner,
  repoName,
  octokit,
}) {
  if (variableExists) {
    await octokit.request(
      "PATCH /repos/{owner}/{repo}/actions/variables/{name}",
      {
        owner: repoOwner,
        repo: repoName,
        name: variableName,
        value: value,
      }
    );
  } else {
    await octokit.request("POST /repos/{owner}/{repo}/actions/variables", {
      owner: repoOwner,
      repo: repoName,
      name: variableName,
      value: value,
    });
  }
}

// This will execute the `checkAndRedeliverWebhooks` function.
(async () => {
  await checkAndRedeliverWebhooks();
})();

Testen des Skripts

Du kannst deinen Workflow manuell auslösen, um das Skript zu testen. Weitere Informationen finden Sie unter Manuelles Ausführen eines Workflows und unter Verwenden von Workflowausführungsprotokollen.

Alternative Methoden

In diesem Beispiel wurden GitHub Actions verwendet, um Anmeldeinformationen sicher zu speichern und das Skript nach einem Zeitplan auszuführen. Wenn du dieses Skript jedoch lieber auf deinem Server ausführen möchtest, das Webhookübermittlungen verarbeitet, kannst du Folgendes tun:

  • Speichere die Anmeldeinformationen auf eine andere sichere Weise, z. B. einen Geheimnis-Manager wie Azure Key Vault. Außerdem musst du das Skript aktualisieren, um von deinem neuen Speicherort aus auf die Anmeldeinformationen zuzugreifen.
  • Führe das Skript nach einem Zeitplan auf deinem Server aus, z. B. mithilfe eines Cron-Auftrags oder eines Aufgabenplaners.
  • Aktualisiere das Skript so, dass die letzte Laufzeit an einem Ort gespeichert wird, auf den dein Server zugreifen und den er aktualisieren kann. Wenn du dich entscheidest, die letzte Laufzeit nicht als GitHub Actions-Geheimnis zu speichern, musst du personal access token nicht verwenden und kannst die API-Aufrufe entfernen, um auf die Konfigurationsvariable zuzugreifen und sie zu aktualisieren.