Expand description
A client for the GitHub Actions Runner Scale Set APIs.
Scale sets let you autoscale self-hosted runners on any infrastructure,
without Kubernetes or actions-runner-controller. This crate covers the
whole API: scale sets, just-in-time (JIT) runner configs, and the message
sessions that tell you how many runners are needed. It follows the
protocol of GitHub’s Go client,
actions/scaleset.
§Overview
- Build a
Clientwith a GitHub App (Credentials::github_app, preferred) or a personal access token. - Create a scale set with
Client::create_runner_scale_set. Its name is the label workflows target withruns-on. - Run a
Listenerwith yourScaler. It opens the message session, acquires jobs, acknowledges messages and recovers from failures. - In the scaler, keep
total_assigned_jobsrunners available: start each with a config fromClient::generate_jit_config.
use std::collections::HashSet;
use scaleset::listener::{Event, Listener, Scaler};
use scaleset::{
BoxError, Client, Credentials, ExposeSecret, JitRunnerSetting, RunnerScaleSetSpec,
ScaleSetId,
};
/// Keeps one runner for every job assigned to the scale set.
struct Autoscaler {
client: Client,
scale_set_id: ScaleSetId,
/// Runners started and not finished yet.
runners: HashSet<String>,
}
impl Scaler for Autoscaler {
type Error = BoxError;
async fn scale(&mut self, event: Event<'_>) -> Result<(), BoxError> {
// Runners are ephemeral: each one leaves when its job completes.
if let Some(message) = event.message() {
for job in message.jobs_completed() {
if let Some(name) = &job.runner_name {
self.runners.remove(name);
}
}
}
let wanted = usize::try_from(event.statistics().total_assigned_jobs)?;
while self.runners.len() < wanted {
let setting = JitRunnerSetting::unique("runner");
let jit = self.client.generate_jit_config(self.scale_set_id, &setting).await?;
// Start a runner (process, container, VM) with
// ACTIONS_RUNNER_INPUT_JITCONFIG set to this value.
let _config = jit.encoded_jit_config.expose_secret();
self.runners.insert(setting.name);
}
Ok(())
}
}
let pem = std::fs::read_to_string("app.pem")?;
let client = Client::builder(
"https://github.com/my-org",
Credentials::github_app("Iv1.abc123", 12345, &pem)?,
)
.build()?;
let scale_set = client
.create_runner_scale_set(&RunnerScaleSetSpec::new("my-scale-set"))
.await?;
let mut scaler = Autoscaler { client: client.clone(), scale_set_id: scale_set.id, runners: HashSet::new() };
Listener::new(client.clone(), scale_set.id, 10)
.run(&mut scaler, async { let _ = tokio::signal::ctrl_c().await; })
.await?;
client.delete_runner_scale_set(scale_set.id).await?;§Layers
| Layer | Use it to |
|---|---|
Listener + Scaler | run an autoscaler; the usual choice |
Subscription | drive the poll / acknowledge loop yourself |
MessageSession | call the message queue endpoints directly |
Client | manage scale sets, runners and JIT configs |
§Transport and retries
The HTTP client is yours (ClientBuilder::http_client, with defaults
from http_client_builder); retries belong to the SDK
(RetryPolicy). Transport errors, 5xx other than 501, and 429 are
retried four times with jittered exponential backoff by default.
Rate-limited responses come back as a RateLimitError (see
Error::rate_limit) and are retried according to RateLimitPolicy.
Client::with_retry_policy changes the policy for some calls only.
§Testing
With the testing feature, testing::Emulator runs a stateful
emulator of GitHub and the Actions service in your test, so an
autoscaler can be tested end to end without network access.
§Logging
The crate logs through tracing; each HTTP request runs in a
scaleset.request span. Install a subscriber to see token refreshes,
polls and retries.
§Features
rustls(default): TLS through rustls.native-tls: TLS through the platform’s library.testing:testing::Emulatorand thescaleset-emulatorbinary.
Enable rustls or native-tls; without TLS the client cannot connect.
Re-exports§
Modules§
- listener
- Turning a scale set’s message queue into scaling decisions.
- testing
testing - A stateful emulator of the scale set APIs, for tests.
Structs§
- Actions
Exception - An exception returned by the Actions service.
- ApiError
- An unsuccessful response from GitHub or the Actions service.
- Client
- A client for the GitHub Actions Runner Scale Set APIs.
- Client
Builder - Builds a
Client. SeeClient::builder. - Credentials
- Credentials for the scale set APIs.
- GitHub
Config Url - A parsed GitHub configuration URL: an enterprise, organization or repository on github.com, GHE.com or GitHub Enterprise Server.
- JitRunner
Config - A just-in-time runner configuration.
- JitRunner
Setting - Settings for a just-in-time runner.
- JobAssigned
- A job was assigned to the scale set.
- JobAvailable
- A job is available to the scale set.
- JobCompleted
- A job finished, or its assignment was canceled before a runner took it.
- JobInfo
- Details shared by all job messages.
- JobRequest
Id - Identifies a job request (
runnerRequestId), as passed toMessageSession::acquire_jobs. - JobStarted
- A runner started a job.
- Label
- A label workflows use in
runs-onto target a scale set. - Message
Id - Identifies a message in a session’s message queue.
- Message
Session - A message session on a scale set’s message queue.
- Rate
Limit Error - A rate-limited response: any 429, or a 403 with
Retry-After,X-RateLimit-Remaining: 0, or a secondary-rate-limit message. - Rate
Limit Rule - Limits the retries for one kind of rate limit. See
RateLimitPolicy::rules. - Retry
Policy - How the SDK retries a request.
- Runner
Group - A runner group.
- Runner
Group Id - Identifies a runner group.
- Runner
Id - Identifies a registered runner.
- Runner
Reference - A registered runner.
- Runner
Scale Set - A runner scale set as returned by the service.
- Runner
Scale SetSpec - The desired state of a scale set, for
Client::create_runner_scale_setandClient::update_runner_scale_set. - Runner
Setting - Runner settings of a scale set.
- Scale
SetId - Identifies a runner scale set.
- Scale
SetMessage - A batch of job messages from the message queue.
- Scale
SetStatistics - Job and runner counts of a scale set.
- Session
Id - Identifies a message session.
- Session
Info - A message session, as created or refreshed by the service.
- Signer
JwtProvider - Builds GitHub App JWTs and has an
Rs256Signersign them, so the private key can stay in a KMS or HSM. - System
Info - Describes the system using the client. It is sent, with the crate
version, as a JSON
User-Agent.
Enums§
- ApiError
Kind - What an
ApiErrormeans, beyond its HTTP status. - Error
- Errors returned by this crate.
- JobMessage
- One job message in a
ScaleSetMessage. - Rate
Limit Kind - Which rate limit rejected a request.
- Rate
Limit Policy - How rate-limited responses are retried.
- Scope
- The level at which a scale set is registered.
Constants§
- DEFAULT_
RUNNER_ GROUP - Name of the default runner group.
- FORCE_
GHES_ ENV - Environment variable that forces GitHub Enterprise Server URL handling, even for hosts that look like github.com.
- LABEL_
TYPE_ SYSTEM - Label type the service assigns to labels created through this API.
- MESSAGE_
POLL_ TIMEOUT - How long one message poll attempt may take. The service holds an idle poll for about 50 seconds; this leaves room above that. Each retry gets a new window.
Traits§
- Expose
Secret - Re-exported for
SecretStringfields such asJitRunnerConfig::encoded_jit_config. Expose a reference to an inner secret - JwtProvider
- Creates short-lived JWTs for GitHub App authentication.
- Rs256
Signer - Signs data with RSASSA-PKCS1-v1_5 and SHA-256 (the JWT
RS256algorithm), for keys that never leave a KMS or HSM.
Functions§
- http_
client_ builder - Returns a
reqwest::ClientBuilderwith the SDK’s defaults: a 5-minute timeout per attempt, a 30-second connect timeout, a 90-second idle pool timeout, TCP keepalive, TLS 1.2 or later, and no redirects (the scale set APIs never redirect, so one is treated as an error rather than followed with credentials attached).
Type Aliases§
- BoxError
- A boxed error, as returned by user-supplied hooks such as a
JwtProvider. - Result
Resultwith this crate’sError.- Secret
String - Re-exported for
SecretStringfields such asJitRunnerConfig::encoded_jit_config. Secret string type.