Skip to main content
Version: Next

Async / Await

Most Aruba Cloud API operations are asynchronous: the HTTP call returns quickly (with a 201 Created or 200 OK), but the resource keeps transitioning through states in the background — CreatingActive, or UpdatingActive, or Deleting → gone — for seconds to several minutes.

The SDK exposes three layers for dealing with this:

LayerWhen to use
WaitUntilReady(ctx)95% of cases — block until the resource is ready (accepts Active, Running, Stopped, NotUsed, Reserved, InUse, Used)
WaitUntilActive(ctx)When you specifically need the Active state only
WaitUntilStates(ctx, []types.State{...}, opts...)Wait for any named states (e.g. []types.State{types.StateStopped})
WaitUntilGone(ctx)After Delete — block until the resource's Get returns HTTP 404 (fully removed)
pkg/async.WaitFor + AsyncClient.AwaitAdvanced — start polling in a background goroutine, do other work, collect the result later

WaitUntilReady

After any Create, Update, or Get, call WaitUntilReady on the returned wrapper to block until the resource reaches any of the 7 healthy settled states: Active, Running, Stopped, NotUsed, Reserved, InUse, or Used.

vpc, err := arubaClient.FromNetwork().VPCs().Create(ctx, vpc)
if err != nil {
log.Fatalf("Create VPC: %v", err)
}

if err := vpc.WaitUntilReady(ctx); err != nil {
log.Fatalf("VPC did not become Ready: %v", err)
}

WaitUntilReady polls the API repeatedly with a fixed delay. When the resource enters a known error terminal state (e.g. "Error", "Failed"), it returns immediately with a descriptive error rather than exhausting all retries.

WaitUntilActive is also available when you need to wait exclusively for the "Active" state — for example, after a power-on operation.

See the API Walkthrough for full Create + poll + Update + Delete examples.

Tuning poll behaviour

Three call options let you override the defaults:

if err := vpc.WaitUntilReady(ctx,
aruba.WithRetries(30), // max polling iterations (default: 60)
aruba.WithBaseDelay(5*time.Second), // fixed delay between polls (default: 10s)
aruba.WithTimeout(3*time.Minute), // hard deadline (default: 600s)
); err != nil {
log.Fatalf("VPC did not become Ready: %v", err)
}

The effective ceiling is min(retries × baseDelay, timeout). At the defaults that is min(60×10s, 600s) = 600s.

For long-running resources (Container Registry, DBaaS, KaaS) that can take 20–40 minutes to converge, use a larger budget:

longWait := []aruba.WaitOption{
aruba.WithTimeout(40 * time.Minute),
aruba.WithRetries(240),
}
if err := reg.WaitUntilReady(ctx, longWait...); err != nil {
log.Fatalf("ContainerRegistry did not become Ready: %v", err)
}

WaitUntilStates

Use WaitUntilStates when you need to wait for one or more specific states — for example, waiting for a stopped state after a power-off:

// Wait for a Cloud Server to fully stop after PowerOff
if err := cs.WaitUntilStates(ctx, []types.State{types.StateStopped}); err != nil {
log.Fatalf("Cloud Server did not stop: %v", err)
}
// Wait until a DBaaS instance finishes an in-progress update
if err := db.WaitUntilActive(ctx,
aruba.WithRetries(120),
aruba.WithBaseDelay(15*time.Second),
); err != nil {
log.Fatalf("DBaaS did not return to Active after update: %v", err)
}

The same error-terminal-state early exit applies: if the resource reaches "Error" or "Failed" while you are waiting for "Stopped", the call returns immediately with an error that names both the actual state and the target states.

WaitUntilActive and WaitUntilReady are convenience wrappers around WaitUntilStates:

  • WaitUntilActive(ctx, opts...) — equivalent to WaitUntilStates(ctx, []types.State{types.StateActive}, opts...)
  • WaitUntilReady(ctx, opts...) — equivalent to WaitUntilStates(ctx, []types.State{types.StateActive, types.StateRunning, types.StateStopped, types.StateNotUsed, types.StateReserved, types.StateInUse, types.StateUsed}, opts...)

WaitUntilGone

Use WaitUntilGone after a Delete call to block until the resource is fully removed — that is, until its Get returns HTTP 404:

if err := arubaClient.FromNetwork().Subnets().Delete(ctx, subnet); err != nil {
log.Printf("Delete subnet: %v", err)
} else if err := subnet.WaitUntilGone(ctx); err != nil {
log.Printf("Subnet not gone: %v", err)
}

WaitUntilGone is available on every resource wrapper that supports polling (see Resources That Support Polling below). It accepts the same WaitOptions as WaitUntilReady. Any error from Get other than HTTP 404 is treated as transient and retried; a 404 signals success.

Project has no polling support and therefore no WaitUntilGone. It is deleted last, with no child left to wait on.


Status Accessors

Every wrapper that supports polling also exposes fine-grained status accessors. You can read these at any time after a Create, Get, Update, or List call:

MethodReturnsTypical use
State()types.State — current stateLogging, conditional branching
PreviousState()types.State — state before the last transitionPost-mortem after a failed wait
FailureReason()string — server-supplied error textSurface to end user / log alert
IsDisabled()boolGate operations when server disables a resource
DisableReasons()[]stringExplain why a resource is disabled

A common pattern — call WaitUntilReady, and if it fails, attach the server's failure reason to the error:

if err := vpc.WaitUntilReady(ctx); err != nil {
reason := vpc.FailureReason()
if reason != "" {
log.Fatalf("VPC failed: %v (reason: %s)", err, reason)
}
log.Fatalf("VPC polling failed: %v", err)
}

Resources That Support Polling

The following resource wrappers support WaitUntilReady, WaitUntilActive, WaitUntilStates, WaitUntilGone, and the status accessors. Resources marked with a special wait method expose an additional named form.

ResourceSpecial waitNotes
CloudServerWaitUntilReadyActive
KaaSWaitUntilReadyActive; can take 10–20 min
ContainerRegistryWaitUntilReadyActive; can take 20–40 min
DBaaSWaitUntilReadyActive; can take 5–15 min
Database
User
Grant
VPC
Subnet
SecurityGroup
SecurityRule
ElasticIPWaitUntilNotUsed, WaitUntilUsedDelegate to WaitUntilStates
BlockStorageWaitUntilNotUsed, WaitUntilUsedDelegate to WaitUntilStates
Snapshot
StorageBackup
StorageRestore
VPCPeering
VPCPeeringRoute
VPNTunnel
VPNRoute
KMS
KmipWaitUntilCertificateAvailableCustom waiter (Family B — no statusMixin); polls KmipResponse.Status directly against an explicit terminal-state map

Project does not support polling. It is synchronously ready immediately after Create returns — no WaitUntilActive call is needed or available.


Caveats

Hydrated wrapper required

WaitUntilReady, WaitUntilActive, WaitUntilStates, and WaitUntilGone only work on wrappers that were returned by an adapter call (Create, Get, Update, or List). Calling any of these methods on a freshly-built request builder returns:

WaitUntilStates: refresh callback not set; resource must be produced by an adapter (Create/Get/Update/List) to support polling

Always use the wrapper returned by the API call:

// Correct — vpc was returned by Create
vpc, err := arubaClient.FromNetwork().VPCs().Create(ctx, myVPC)
vpc.WaitUntilReady(ctx)

// Wrong — myVPC is a request builder, not an adapter response
myVPC := aruba.NewVPC().Named("x")
myVPC.WaitUntilReady(ctx) // returns "refresh callback not set"

Constant poll cadence

Polling uses a fixed delay (no exponential backoff). If you are hitting API rate limits, increase WithBaseDelay rather than expecting the SDK to back off automatically.

Context cancellation

All polling respects the ctx deadline and cancellation. If the context expires mid-poll the call returns ctx.Err() (typically context.DeadlineExceeded or context.Canceled).


Advanced: concurrent and custom polling

WaitUntilReady, WaitUntilActive, and WaitUntilStates block the calling goroutine. When you need to start multiple waits concurrently, or poll an arbitrary condition (not just a resource state), drop down to pkg/async. That layer works directly with *types.Response[T] and is documented separately — see Working at Low Level.


See Also

  • API Walkthrough — full Create + WaitUntilReady + Update + Delete lifecycle example
  • Response Handling — how *aruba.HTTPError propagates through WaitUntilReady when the API returns 4xx/5xx
  • Working at Low Level — background polling with pkg/async, accessing non-promoted wire fields