Scaling on GCP

Resize a Google Compute Engine managed instance group with a small Oban.Pro.Cloud module built on Req. The project, zone, and group are resolved in init/1, and scale/2 posts the desired size to the resize endpoint.

def deps do
  [
    {:req, "~> 0.5"}
  ]
end

The Module

The Oban.Pro.Cloud.init/1 callback reads the API key from the system environment and leaves the project, zone, and instance group manager to pass through as options. The Oban.Pro.Cloud.scale/2 callback posts the desired size and returns {:ok, conf} so the scaler can track the response.

defmodule MyApp.GCP do
  @behaviour Oban.Pro.Cloud

  @impl Oban.Pro.Cloud
  def init(opts) do
    opts
    |> Keyword.put_new(:api_key, System.fetch_env!("GCP_API_KEY"))
    |> Map.new()
  end

  @impl Oban.Pro.Cloud
  def scale(desired, conf) do
    url =
      "https://compute.googleapis.com/compute/v1/projects/#{conf.project_id}/zones/" <>
        "#{conf.zone}/instanceGroupManagers/#{conf.instance_group_manager}/resize"

    case Req.post(url, params: [size: desired, key: conf.api_key]) do
      {:ok, %{status: status}} when status in 200..299 -> {:ok, conf}
      {:ok, response} -> {:error, response}
      {:error, reason} -> {:error, reason}
    end
  end
end

An API key keeps the example short, but it only works where Compute Engine accepts one. For service-account auth, swap the key param for an OAuth token in an authorization header and mint it however your app already talks to Google.

Using It

Point a scaler at the module and pass the group it should resize:

cloud = {MyApp.GCP, project_id: "my-project", zone: "us-east1-b", instance_group_manager: "workers"}

{DynamicScaler, scalers: [range: 1..5, cloud: cloud]}