---
# System prepended metadata

title: Notes on buildkite APIs

---

# Notes on buildkite APIs

## buildkite-jobify
### Config

Takes a TOML config with:

- organization
- api token
- an array of the pipelines to watch
- namespace to create jobs in
- optional cluster identifier, agents can specify clusters?

### Structure

**Monitor** is responsible for periodically fetching all the pipelines, polling them for builds, and sending them to the Jobifier. Uses GraphQL API to poll. It keeps track of *known* builds, 

**Jobifier** is responsible for receiving builds and turning them into jobs.

**Scheduler** takes jobs from the monitor and dispatches them to the jobifier

### GraphQL API

Example query for queued/failed builds and their jobs:

```graphql!
query GetBuilds($id: ID = "UGlwZWxpbmUtLS0wMTg0NjI3NC0wOWJjLTRjN2EtYmI5MC1jYjMxN2U1NjlmZTc=") {
  node(id: $id) {
  __typename
      ... on Pipeline {
      builds(first: 1, state: [RUNNING, FAILING]) {
        count
        edges {
          node {
            uuid
            message
            state
            commit
            metaData(first: 10) {
              count
              edges {
                node {
                  key
                  value
                }
              }
            }
            jobs(first: 1) {
              count
              edges {
                node {
                  __typename
                  ... on JobTypeCommand {
                    uuid
                    label
                    state
                    agentQueryRules
                    exitStatus
                    agent {
                      name
                    }
                    env
                  }
                }
              }
              pageInfo {
                hasNextPage
              }
            }
          }
        }
      }
    }
  }
}
```

Response:

```json!
{
  "data": {
    "node": {
      "__typename": "Pipeline",
      "builds": {
        "count": 1,
        "edges": [
          {
            "node": {
              "uuid": "018476d3-6f90-441a-8b80-7c525e1c2eb8",
              "message": "Update README.md",
              "state": "RUNNING",
              "commit": "7b71ee28a15ef298fb511fb025bfbbdb5b671a27",
              "metaData": {
                "count": 0,
                "edges": []
              },
              "triggeredFrom": null,
              "jobs": {
                "count": 5,
                "edges": [
                  {
                    "node": {
                      "__typename": "JobTypeCommand",
                      "uuid": "018476d4-3ba2-4e47-adec-3cdf277190da",
                      "label": ":golang:",
                      "state": "SCHEDULED",
                      "agentQueryRules": [
                        "queue=3462986656"
                      ],
                      "exitStatus": null,
                      "agent": null,
                      "env": [
                        "CI=true",
                        "BUILDKITE=true",
                        "BUILDKITE_ORGANIZATION_SLUG=superorbital",
                        "BUILDKITE_PIPELINE_SLUG=buildkite-gh-actions",
                        "BUILDKITE_PIPELINE_NAME=buildkite-gh-actions",
                        "BUILDKITE_PIPELINE_ID=01846274-09bc-4c7a-bb90-cb317e569fe7",
                        "BUILDKITE_PIPELINE_PROVIDER=github",
                        "BUILDKITE_PIPELINE_DEFAULT_BRANCH=main",
                        "BUILDKITE_REPO=https://github.com/benmoss/buildkite-gh-actions",
                        "BUILDKITE_BUILD_ID=018476d3-6f90-441a-8b80-7c525e1c2eb8",
                        "BUILDKITE_BUILD_NUMBER=33",
                        "BUILDKITE_BUILD_URL=https://buildkite.com/superorbital/buildkite-gh-actions/builds/33",
                        "BUILDKITE_BRANCH=main",
                        "BUILDKITE_TAG=",
                        "BUILDKITE_COMMIT=7b71ee28a15ef298fb511fb025bfbbdb5b671a27",
                        "BUILDKITE_MESSAGE=Update README.md",
                        "BUILDKITE_SOURCE=ui",
                        "BUILDKITE_BUILD_AUTHOR=",
                        "BUILDKITE_BUILD_AUTHOR_EMAIL=",
                        "BUILDKITE_BUILD_CREATOR=Ben Moss",
                        "BUILDKITE_BUILD_CREATOR_EMAIL=ben.moss@superorbital.io",
                        "BUILDKITE_REBUILT_FROM_BUILD_ID=",
                        "BUILDKITE_REBUILT_FROM_BUILD_NUMBER=",
                        "BUILDKITE_PULL_REQUEST=false",
                        "BUILDKITE_PULL_REQUEST_BASE_BRANCH=",
                        "BUILDKITE_PULL_REQUEST_REPO=",
                        "BUILDKITE_TRIGGERED_FROM_BUILD_ID=",
                        "BUILDKITE_TRIGGERED_FROM_BUILD_NUMBER=",
                        "BUILDKITE_TRIGGERED_FROM_BUILD_PIPELINE_SLUG=",
                        "BUILDKITE_JOB_ID=018476d4-3ba2-4e47-adec-3cdf277190da",
                        "BUILDKITE_LABEL=:golang:",
                        "BUILDKITE_COMMAND=go test -v .",
                        "BUILDKITE_ARTIFACT_PATHS=",
                        "BUILDKITE_RETRY_COUNT=3",
                        "BUILDKITE_TIMEOUT=false",
                        "BUILDKITE_STEP_KEY=",
                        "BUILDKITE_STEP_ID=018476d3-7de3-4e5b-82c8-c3801a0a46b4",
                        "BUILDKITE_PROJECT_SLUG=superorbital/buildkite-gh-actions",
                        "BUILDKITE_PROJECT_PROVIDER=github",
                        "BUILDKITE_SCRIPT_PATH=go test -v ."
                      ]
                    }
                  }
                ],
                "pageInfo": {
                  "hasNextPage": true
                }
              }
            }
          }
        ]
      }
    }
  }
}
```

## buildscaler
Uses the agent `/metrics` endpoint to get info about agents/builds.

Example request:
```bash!
http https://agent.buildkite.com/v3/metrics Authorization:"Token $TOKEN"
```

Example response:

```json!
{
    "agents": {
        "busy": 1,
        "idle": 0,
        "queues": {
            "default": {
                "busy": 1,
                "idle": 0,
                "total": 1
            }
        },
        "total": 1
    },
    "jobs": {
        "queues": {
            "3462916696": {
                "running": 1,
                "scheduled": 0,
                "total": 1,
                "waiting": 0
            }
        },
        "running": 1,
        "scheduled": 0,
        "total": 1,
        "waiting": 0
    },
    "organization": {
        "slug": "superorbital"
    }
}
```

## What we need
The GraphQL API is what we need, since we can get at the full job spec before it has even run. 

We can use this to make decisions about whether we run it in a default agent container, using the job's PodSpec, or not at all.

## Open questions
- Polling first seems like the simplest option
    - A webhook is possible, but we'd need some way of getting the result