Documentation Index
Fetch the complete documentation index at: https://mintlify.com/superfly/sprites-go/llms.txt
Use this file to discover all available pages before exploring further.
Services are named, long-running processes managed by the Sprite runtime. Unlike ad-hoc commands run with sprite.Command, a service has a persistent definition — including the command, arguments, HTTP port, and startup dependencies — that survives restarts and can be controlled independently. The SDK provides functions to create, start, stop, signal, and stream logs from services.
Service concepts
A service definition is described by ServiceRequest:
type ServiceRequest struct {
Cmd string // The executable to run
Args []string // Arguments passed to the executable
Needs []string // Names of other services that must be running first
HTTPPort *int // Port to monitor for HTTP readiness (optional)
}
At runtime, the Sprite tracks each service’s state in ServiceState:
type ServiceState struct {
Name string
Status string // "stopped", "starting", "running", "stopping", "failed"
PID int
StartedAt time.Time
Error string
RestartCount int
NextRestartAt time.Time
}
GetService and ListServices return ServiceWithState, which embeds both the definition and the runtime state.
Listing services
ListServices returns all services defined on the Sprite along with their current runtime state.
services, err := sprite.ListServices(ctx)
if err != nil {
log.Fatal(err)
}
for _, svc := range services {
status := "unknown"
if svc.State != nil {
status = svc.State.Status
}
fmt.Printf("%s: %s\n", svc.Name, status)
}
Getting a specific service
svc, err := sprite.GetService(ctx, "web")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Status: %s, PID: %d\n", svc.State.Status, svc.State.PID)
Creating a service
CreateService registers the service definition on the Sprite and returns a *ServiceStream that emits log events while the server processes the request. Call ProcessAll or Next to drain the stream — you must consume or close the stream before it is garbage-collected.
port := 8080
stream, err := sprite.CreateService(ctx, "web", &sprites.ServiceRequest{
Cmd: "node",
Args: []string{"server.js"},
HTTPPort: &port,
})
if err != nil {
log.Fatal(err)
}
err = stream.ProcessAll(func(event *sprites.ServiceLogEvent) error {
fmt.Printf("[%s] %s\n", event.Type, event.Data)
return nil
})
if err != nil {
log.Fatal(err)
}
Calling CreateService a second time with the same name updates the service definition. The service must not be running when you update it.
Service with dependencies
Use Needs to declare that one service must be running before another starts. The Sprite runtime starts dependencies in the correct order.
stream, err := sprite.CreateService(ctx, "worker", &sprites.ServiceRequest{
Cmd: "/app/worker",
Args: []string{"--queue", "default"},
Needs: []string{"redis", "postgres"},
})
Starting a service
StartService starts the named service and returns a *ServiceStream. Stream events flow until the service is running (or fails to start).
stream, err := sprite.StartService(ctx, "web")
if err != nil {
log.Fatal(err)
}
defer stream.Close()
err = stream.ProcessAll(func(event *sprites.ServiceLogEvent) error {
switch event.Type {
case "stdout", "stderr":
fmt.Print(event.Data)
case "started":
fmt.Println("Service is running")
case "error":
return fmt.Errorf("service error: %s", event.Data)
}
return nil
})
Stopping a service
StopService sends a stop signal to the service and returns a stream of events until the process exits.
stream, err := sprite.StopService(ctx, "web")
if err != nil {
log.Fatal(err)
}
err = stream.ProcessAll(func(event *sprites.ServiceLogEvent) error {
fmt.Printf("[%s] %s\n", event.Type, event.Data)
return nil
})
Sending a signal
SignalService sends a POSIX signal to a running service by name. Pass the signal as a string, for example "HUP" or "USR1". Valid signal names match those used by cmd.Signal: INT, TERM, HUP, KILL, QUIT, USR1, USR2.
err := sprite.SignalService(ctx, "web", "HUP")
if err != nil {
log.Fatal(err)
}
SignalService returns an error if the service is not running. Check the service state with GetService first if the running status is uncertain.
Deleting a service
DeleteService removes the service definition from the Sprite. The service must be stopped first.
err := sprite.DeleteService(ctx, "web")
if err != nil {
log.Fatal(err)
}
Working with ServiceStream
ServiceStream is returned by CreateService, StartService, and StopService. It delivers a sequence of ServiceLogEvent values parsed from the server’s newline-delimited JSON stream.
Reading events one at a time
for {
event, err := stream.Next()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
fmt.Printf("type=%s data=%q\n", event.Type, event.Data)
}
stream.Close()
Processing all events with a handler
ProcessAll calls your handler for every event and closes the stream when it returns.
err := stream.ProcessAll(func(event *sprites.ServiceLogEvent) error {
if event.Type == "exit" && event.ExitCode != nil {
fmt.Printf("Process exited with code %d\n", *event.ExitCode)
}
return nil
})
Returning a non-nil error from the handler stops processing and propagates the error from ProcessAll.
ServiceLogEvent fields
type ServiceLogEvent struct {
Type string // See event types below
Data string // Log line content (for stdout/stderr/error)
ExitCode *int // Set when Type is "exit"
Timestamp int64 // Unix timestamp in milliseconds
LogFiles map[string]string // Paths to persisted log files (when present)
}
Event types:
| Type | When emitted |
|---|
stdout | A line written to the process’s standard output |
stderr | A line written to the process’s standard error |
started | The service process has started successfully |
stopping | A stop request has been sent to the process |
stopped | The process has stopped cleanly |
exit | The process exited; check ExitCode |
error | An error occurred in the service runtime |
complete | The stream is finished; no more events will follow |
Complete example: create, start, and stream logs
The following example registers a web service, starts it, and streams its output until it is running.
package main
import (
"context"
"fmt"
"io"
"log"
sprites "github.com/superfly/sprites-go"
)
func main() {
client := sprites.New("your-auth-token")
sprite := client.Sprite("my-sprite")
ctx := context.Background()
// Create the service definition
port := 8080
createStream, err := sprite.CreateService(ctx, "web", &sprites.ServiceRequest{
Cmd: "node",
Args: []string{"server.js"},
HTTPPort: &port,
})
if err != nil {
log.Fatal("create:", err)
}
if err := createStream.ProcessAll(func(e *sprites.ServiceLogEvent) error {
fmt.Printf("create [%s] %s\n", e.Type, e.Data)
return nil
}); err != nil {
log.Fatal("create stream:", err)
}
// Start the service and stream logs
startStream, err := sprite.StartService(ctx, "web")
if err != nil {
log.Fatal("start:", err)
}
for {
event, err := startStream.Next()
if err == io.EOF {
break
}
if err != nil {
log.Fatal("stream:", err)
}
switch event.Type {
case "stdout":
fmt.Print("[out] ", event.Data)
case "stderr":
fmt.Print("[err] ", event.Data)
case "started":
fmt.Println("Service is running")
case "error":
log.Fatal("service error:", event.Data)
}
}
startStream.Close()
// Check the running state
svc, err := sprite.GetService(ctx, "web")
if err != nil {
log.Fatal("get:", err)
}
fmt.Printf("PID %d, restarts: %d\n", svc.State.PID, svc.State.RestartCount)
}