# Operations API Guide
The Operations API provides tracking and management for long-running operations like video generation, file imports, and model tuning.
## Overview
Long-running operations are used when:
- Generating video content
- Importing large files
- Tuning custom models
- Any API call that may take significant time
The Operations API allows you to:
- Check operation status and progress
- Wait for completion with configurable polling
- Cancel running operations
- List and manage active operations
## Quick Start
```elixir
alias Gemini.APIs.Operations
alias Gemini.Types.Operation
# Get operation status
{:ok, op} = Operations.get("operations/abc123")
IO.puts("Done: #{op.done}")
# Wait for completion
{:ok, completed} = Operations.wait("operations/abc123")
if Operation.succeeded?(completed) do
IO.puts("Operation completed successfully!")
IO.inspect(completed.response)
else
IO.puts("Operation failed: #{completed.error.message}")
end
```
## Operation States
Operations have a simple state model:
| Field | Description |
|-------|-------------|
| `done: false` | Operation is still running |
| `done: true, error: nil` | Operation succeeded |
| `done: true, error: %{...}` | Operation failed |
## Getting Operation Status
```elixir
{:ok, op} = Operations.get("operations/abc123")
IO.puts("Name: #{op.name}")
IO.puts("Done: #{op.done}")
# Check for progress in metadata
if progress = Operation.get_progress(op) do
IO.puts("Progress: #{progress}%")
end
# Check result
cond do
Operation.running?(op) ->
IO.puts("Still running...")
Operation.succeeded?(op) ->
IO.puts("Success!")
IO.inspect(op.response)
Operation.failed?(op) ->
IO.puts("Failed: #{op.error.message}")
end
```
## Waiting for Completion
### Simple Wait
```elixir
{:ok, completed} = Operations.wait("operations/abc123")
```
### With Options
```elixir
{:ok, completed} = Operations.wait("operations/abc123",
poll_interval: 10_000, # Check every 10 seconds
timeout: 600_000, # 10 minute timeout
on_progress: fn op ->
if progress = Operation.get_progress(op) do
IO.puts("Progress: #{Float.round(progress, 1)}%")
else
IO.puts("Running... done=#{op.done}")
end
end
)
```
### With Exponential Backoff
For long-running operations, use backoff to reduce API calls:
```elixir
{:ok, completed} = Operations.wait_with_backoff("operations/abc123",
initial_delay: 1_000, # Start at 1 second
max_delay: 60_000, # Cap at 1 minute
multiplier: 2.0, # Double each time
timeout: 3_600_000, # 1 hour timeout
on_progress: fn op ->
IO.puts("Checking... done=#{op.done}")
end
)
```
## Listing Operations
### List with Pagination
```elixir
{:ok, response} = Operations.list()
Enum.each(response.operations, fn op ->
status = if op.done, do: "done", else: "running"
IO.puts("#{op.name}: #{status}")
end)
# With options
{:ok, response} = Operations.list(page_size: 10)
if ListOperationsResponse.has_more_pages?(response) do
{:ok, page2} = Operations.list(page_token: response.next_page_token)
end
```
### List All Operations
```elixir
{:ok, all_ops} = Operations.list_all()
running = Enum.filter(all_ops, &Operation.running?/1)
IO.puts("Running operations: #{length(running)}")
```
## Cancelling Operations
```elixir
case Operations.cancel("operations/abc123") do
:ok -> IO.puts("Operation cancelled")
{:error, reason} -> IO.puts("Failed to cancel: #{inspect(reason)}")
end
```
## Deleting Operations
Clean up completed operations:
```elixir
:ok = Operations.delete("operations/abc123")
```
## Operation Helper Functions
```elixir
alias Gemini.Types.Operation
# Check state
Operation.complete?(op) # Done (success or failure)?
Operation.succeeded?(op) # Completed successfully?
Operation.failed?(op) # Completed with error?
Operation.running?(op) # Still in progress?
# Get progress percentage (from metadata)
Operation.get_progress(op) # 75.5 or nil
# Get operation ID
Operation.get_id(op) # "abc123" from "operations/abc123"
```
## Progress Tracking
Operations may include progress information in their metadata:
```elixir
{:ok, op} = Operations.get("operations/abc123")
# The get_progress function checks multiple common fields
progress = Operation.get_progress(op)
# Checks: metadata["progress"], metadata["progressPercent"],
# metadata["completionPercentage"]
if progress do
IO.puts("Progress: #{Float.round(progress, 1)}%")
end
```
## Error Handling
### Operation Errors
```elixir
{:ok, op} = Operations.get("operations/abc123")
if Operation.failed?(op) do
error = op.error
IO.puts("Error code: #{error.code}")
IO.puts("Message: #{error.message}")
if error.details do
Enum.each(error.details, fn detail ->
IO.puts("Detail: #{inspect(detail)}")
end)
end
end
```
### API Errors
```elixir
case Operations.get("operations/abc123") do
{:ok, op} ->
IO.inspect(op)
{:error, {:http_error, 404, _}} ->
IO.puts("Operation not found")
{:error, {:http_error, status, body}} ->
IO.puts("HTTP error #{status}: #{inspect(body)}")
{:error, :timeout} ->
IO.puts("Request timed out")
{:error, reason} ->
IO.puts("Failed: #{inspect(reason)}")
end
```
## Common Use Cases
### Video Generation
```elixir
# Start video generation (returns operation)
{:ok, op} = start_video_generation(prompt)
# Wait for completion with progress
{:ok, completed} = Operations.wait(op.name,
poll_interval: 30_000,
on_progress: fn op ->
if progress = Operation.get_progress(op) do
IO.puts("Video generation: #{progress}%")
end
end
)
# Get the generated video URI from response
video_uri = completed.response["generatedVideo"]["uri"]
```
### Model Tuning
```elixir
# Start tuning job (returns operation)
{:ok, op} = start_tuning_job(config)
# Wait with exponential backoff (tuning can take hours)
{:ok, completed} = Operations.wait_with_backoff(op.name,
initial_delay: 60_000, # Start at 1 minute
max_delay: 300_000, # Cap at 5 minutes
timeout: 86_400_000, # 24 hour timeout
on_progress: fn op ->
IO.puts("Tuning in progress...")
end
)
```
## Best Practices
1. **Use appropriate polling intervals** - Don't poll too frequently for long operations
2. **Implement progress callbacks** - Keep users informed of progress
3. **Handle timeouts gracefully** - Operations can exceed expected duration
4. **Use exponential backoff** - For very long operations to reduce API calls
5. **Clean up completed operations** - Delete when results are processed
6. **Store operation names** - In case you need to resume monitoring later
## API Reference
- `Gemini.APIs.Operations.get/2` - Get operation status
- `Gemini.APIs.Operations.list/1` - List operations
- `Gemini.APIs.Operations.list_all/1` - List all operations
- `Gemini.APIs.Operations.cancel/2` - Cancel an operation
- `Gemini.APIs.Operations.delete/2` - Delete an operation
- `Gemini.APIs.Operations.wait/2` - Wait for completion
- `Gemini.APIs.Operations.wait_with_backoff/2` - Wait with exponential backoff