Fulfills a GitHub workflow_job webhooks into a Pub/Sub queue.

GitHub Workflow Job to Pub/Sub

The GitHub Workflow Job to Pub/Sub is a small service that fulfills a GitHub workflow_job webhook.

  • When a job is queued, it inserts one message onto a Pub/Sub topic.

  • When a job is finished, it acknowledges one message from a Pub/Sub subscription.

This means that, at any time, the number of unacknowledged messages in the Pub/Sub topic corresponds to the number of queued or active GitHub Actions jobs. You can use this property as an indicator in an auto-scaling metric or a means to queue new ephemeral workers.

Deployment

This deployment example uses Google Cloud and [Cloud Run][cloud-run] to deploy and manage the proxy.

  1. Create or use an existing Google Cloud project:

    export PROJECT_ID="..."
  2. Enable required APIs:

    gcloud services enable --project="${PROJECT_ID}" \
      artifactregistry.googleapis.com \
      cloudbuild.googleapis.com \
      pubsub.googleapis.com \
      run.googleapis.com \
      secretmanager.googleapis.com
  3. Create a service account to run the receiver:

    gcloud iam service-accounts create "gh-webhook-receiver" \
      --description="GitHub webhook receiver" \
      --project="${PROJECT_ID}"
  4. Create a GitHub Webhook secret and store it in Google Secret Manager. This secret can be any value.

    echo -n "<YOUR SECRET>" | gcloud secrets create "gh-webhook-secret" \
      --project="${PROJECT_ID}" \
      --data-file=-

    If you do not have a secret, you can randomly generate a secret using openssl:

    openssl rand -base64 32
  5. Grant the service account permissions to access the secret:

    gcloud secrets add-iam-policy-binding "gh-webhook-secret" \
      --project="${PROJECT_ID}" \
      --role="roles/secretmanager.secretAccessor" \
      --member="serviceAccount:gh-webhook-receiver@${PROJECT_ID}.iam.gserviceaccount.com"
  6. Create a Pub/Sub topic:

    gcloud pubsub topics create "gh-topic" \
      --project="${PROJECT_ID}" \
      --message-encoding="JSON"
  7. Grant the service account permissions to publish to the topic:

    gcloud pubsub topics add-iam-policy-binding "gh-topic" \
      --project="${PROJECT_ID}" \
      --role="roles/pubsub.publisher" \
      --member="serviceAccount:gh-webhook-receiver@${PROJECT_ID}.iam.gserviceaccount.com"
  8. Create a Pub/Sub subscription:

    gcloud pubsub topics create "gh-subscription" \
      --project="${PROJECT_ID}" \
      --topic="gh-topic" \
      --ack-deadline="10s" \
      --message-retention-duration="1800s" \
      --expiration-period="never" \
      --min-retry-delay="5s" \
      --max-retry-delay="30s"
  9. Grant the service account permissions to pull from the subscription:

    gcloud pubsub subscriptions add-iam-policy-binding "gh-subscription" \
      --project="${PROJECT_ID}" \
      --role="roles/pubsub.subscriber" \
      --member="serviceAccount:gh-webhook-receiver@${PROJECT_ID}.iam.gserviceaccount.com"
  10. Create a repository in Artifact Registry to store the container:

    gcloud artifacts repositories create "gh-webhook-receiver" \
      --project="${PROJECT_ID}" \
      --repository-format="docker" \
      --location="us" \
      --description="GitHub webhook receiver"
  11. Build and push the container:

    gcloud builds submit . \
      --project="${PROJECT_ID}" \
      --tag="us-docker.pkg.dev/${PROJECT_ID}/gh-webhook-receiver/gh-webhook-receiver"
  12. Deploy the service and attach the secret (see Configuration for more information on available options):

    gcloud beta run deploy "gh-webhook-receiver" \
      --quiet \
      --project="${PROJECT_ID}" \
      --region="us-east1" \
      --set-secrets="GITHUB_WEBHOOK_SECRET=gh-webhook-secret:1" \
      --set-env-vars="PUBSUB_TOPIC_NAME=projects/${PROJECT_ID}/topics/gh-topic,PUBSUB_SUBSCRIPTION_NAME=projects/${PROJECT_ID}/subscriptions/gh-subscription" \
      --image="us-docker.pkg.dev/${PROJECT_ID}/gh-webhook-receiver/gh-webhook-receiver" \
      --service-account="gh-webhook-receiver@${PROJECT_ID}.iam.gserviceaccount.com" \
      --allow-unauthenticated

    Take note of the URL. It is important to note that this is a publicly-accessible URL.

  13. Create an organization webhook on GitHub:

    • Payload URL: URL for the Cloud Run service above.
    • Content type: application/json
    • Secret: value from above
    • Events: select "individual events" and then choose only "Workflow jobs"

Configuration

  • GITHUB_WEBHOOK_SECRET - this is the secret key to use for authenticating the webhook's HMAC. This must match the value given to GitHub when configuring the webhook. It is very important that you choose a high-entropy secret, because your service must be publicly accessible.

  • PUBSUB_TOPIC_NAME - this is the name of the topic on which to publish. This must be the full topic name including the project (e.g. projects/my-project/topics/my-topic).

  • PUBSUB_SUBSCRIPTION_NAME - this is the name of the subscription on which to pull and acknowledge. This must be the full subscription name including the project (e.g. projects/my-project/subscriptions/my-subscription).

FAQ

Q: Why is Pub/Sub necessary? Why not just have the service create ephemeral runners or scale a VM pool directly?
A: GitHub has a timeout of 10 seconds for webhook responses, and strongly recommends asynchronous processing. Modifying an autoscaling group or spinning up a new virtual machine will almost always exceed this timeout.

Similar Resources

golang long polling library. Makes web pub-sub easy via HTTP long-poll server :smiley: :coffee: :computer:

golang long polling library.  Makes web pub-sub easy via HTTP long-poll server :smiley: :coffee: :computer:

golongpoll Golang long polling library. Makes web pub-sub easy via an HTTP long-poll server. New in v1.1 Deprecated CreateManager and CreateCustomMana

Jan 6, 2023

nanoQ — high-performance brokerless Pub/Sub for streaming real-time data

nanoQ — high-performance brokerless Pub/Sub for streaming real-time data nanoQ is a very minimalistic (opinionated/limited) Pub/Sub transport library.

Nov 9, 2022

Collection of personal Dapr demos (bindings, state, pub/sub, service-to-service invocation)

Dapr demos Collection of personal Dapr demos. Note, some of these demos require latest version of Dapr, Ingress gateway, Observability components, or

Dec 10, 2022

Simple synchronous event pub-sub package for Golang

event-go Simple synchronous event pub-sub package for Golang This is a Go language package for publishing/subscribing domain events. This is useful to

Jun 16, 2022

This is a Pub/Sub for the Watermill project which uses the Bolt database.

This is a Pub/Sub for the Watermill project which uses the Bolt database.

Watermill Bolt Pub/Sub This is a Pub/Sub for the Watermill project which uses the Bolt database.

Jun 13, 2022

a tcp framework which support pub/sub and request/reply

支持 事件订阅/请求回应 的的TCP通讯框架 源于 zinx 的业务定制版本 TCP 通讯框架 特点 服务端/客户端均支持订阅事件通讯. 服务端支持 Broadcast 方式发送信息到客户端. 客户端均支持 Request/Reply 方式与服务端通讯 服务端用多个worker去处理客户端的请求 目

Oct 9, 2021

ntfy is a super simple pub-sub notification service. It allows you to send desktop notifications via scripts.

ntfy ntfy (pronounce: notify) is a super simple pub-sub notification service. It allows you to send desktop and (soon) phone notifications via scripts

Jan 9, 2023

Google pub/sub service easy way to use

easy pubsub Installation go get github.com/buraksecer/go-easy-pubsub v0.0.2 Example Firstly, you must Init new topic operation. topic.Init(clientId)

Nov 24, 2022

A basic pub-sub project using NATS

NATS Simple Pub-Sub Mechanism This is a basic pub-sub project using NATS. There is one publisher who publishes a "Hello World" message to a subject ca

Dec 13, 2021

Sample program of GCP pub/sub client with REST API

GCP pub/sub sample using REST API in Go GCP pub/sub publisher and subscriber sample programs. These use REST API and don't use pub/sub client library

Oct 12, 2021

Simple-messaging - Brokerless messaging. Pub/Sub. Producer/Consumer. Pure Go. No C.

Simple Messaging Simple messaging for pub/sub and producer/consumer. Pure Go! Usage Request-Response Producer: consumerAddr, err := net.ResolveTCPAddr

Jan 20, 2022

Reads JSON object (stream) from file/stdin and routes it/them to GCP Pub/Sub topics.

json2pubsub Publish JSON object (stream) into GCP Pub/Sub topic based on a field value. Usage: json2pubsub --project=STRING mapping ... Reads JSON

Nov 3, 2022

A simple in-process pub/sub for golang

go-pub-sub A simple in-process pub/sub for golang Motivation Call it somewhere between "I spent no more than 5 minutes looking for one that existed" a

Jan 25, 2022

Kafka, Beanstalkd, Pulsar Pub/Sub framework

go-queue Kafka, Beanstalkd, Pulsar Pub/Sub framework.

Sep 17, 2022

This library implements the pub/sub pattern in a generic way. It uses Go's generic types to declare the type of the event.

observer This library implements the pub/sub pattern in a generic way. It uses Go's generic types to declare the type of the event. Usage go get githu

Nov 16, 2022

CLI tool for generating random messages with rules & publishing to the cloud services (SQS,SNS,PUB/SUB and etc.)

Randomsg A CLI tool to generate random messages and publish to cloud services like (SQS,SNS,PUB/SUB and etc.). TODO Generation of nested objects is no

Sep 22, 2022

A gRPC based pub/sub messaging system

Arrebato Arrebato is a gRPC based pub/sub messaging system with an emphasis on strong message typing & message verification using public-key cryptogra

Aug 3, 2022

✏️ CLI tool to split a file into smaller sub-files

filesplit CLI tool to split a file into smaller sub-files Build $ go build Usage filesplit [mode] [-F, --file] [-N, --number] Examples # Split foo.txt

Apr 20, 2022

Unlimited job queue for go, using a pool of concurrent workers processing the job queue entries

kyoo: A Go library providing an unlimited job queue and concurrent worker pools About kyoo is the phonetic transcription of the word queue. It provide

Dec 21, 2022
Celery Distributed Task Queue in Go
Celery Distributed Task Queue in Go

gocelery Go Client/Server for Celery Distributed Task Queue Why? Having been involved in several projects migrating servers from Python to Go, I have

Jan 1, 2023
A lightweight job scheduler based on priority queue with timeout, retry, replica, context cancellation and easy semantics for job chaining. Build for golang web apps.

Table of Contents Introduction What is RIO? Concern An asynchronous job processor Easy management of these goroutines and chaining them Introduction W

Dec 9, 2022
YTask is an asynchronous task queue for handling distributed jobs in golang
YTask is an asynchronous task queue for handling distributed jobs in golang

YTask is an asynchronous task queue for handling distributed jobs in golang

Dec 24, 2022
a self terminating concurrent job queue for indeterminate workloads in golang

jobtracker - a self terminating concurrent job queue for indeterminate workloads in golang This library is primarily useful for technically-recursive

Sep 6, 2022
Redisq is a queue-over-redis that provides simple way to works with queues stored in Redis.

Redisq is a queue-over-redis that provides simple way to works with queues stored in Redis.

Feb 10, 2022
Gotask - A simple task queue is stripped when the program is written to achieve the task delivery function
Gotask - A simple task queue is stripped when the program is written to achieve the task delivery function

gotask The simple task queue is stripped when the program is written to achieve

Feb 14, 2022
Gron transforms JSON into discrete assignments to make it easier to grep

gron Make JSON greppable! gron transforms JSON into discrete assignments to make it easier to grep for what you want and see the absolute 'path' to it

Nov 11, 2021
Gron - Gron transforms JSON into discrete assignments to make it easier to grep

gron Make JSON greppable! gron transforms JSON into discrete assignments to make

Jan 6, 2022
Feb 14, 2022
A pizza store design using NATS pub sub queue.
A pizza store design using NATS pub sub queue.

A pizza store design using NATS pub sub queue.

Oct 12, 2022