Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -130,31 +130,57 @@ func Run(ctx context.Context, cfg Config) error {

### 5. Call the Service

These are ugly, they're working on generating proper clients from the proto definitions
https://github.com/restatedev/sdk-go/issues/103
The Restate SDK now generates typed ingress clients from proto definitions. Use these for type-safe, clean service calls.

**Blocking call:**
**Setup - Create a helper method in your service:**

```go
response, err := restateingress.Object[*hydrav1.YourRequest, *hydrav1.YourResponse](
restateClient,
"hydra.v1.YourService",
keyValue,
"YourOperation",
).Request(ctx, request)
// In your service struct (e.g., apps/ctrl/services/deployment/service.go)
type Service struct {
restate *restateingress.Client
// ... other fields
}

// Helper method to get typed client
func (s *Service) yourServiceClient(key string) hydrav1.YourServiceIngressClient {
return hydrav1.NewYourServiceIngressClient(s.restate, key)
}
```

**Blocking call (Request):**

```go
response, err := s.yourServiceClient(keyValue).
YourOperation().
Request(ctx, &hydrav1.YourRequest{
KeyField: keyValue,
})
if err != nil {
return nil, fmt.Errorf("operation failed: %w", err)
}
```

**Fire-and-forget:**
**Fire-and-forget (Send):**

```go
invocation := restateingress.WorkflowSend[*hydrav1.YourRequest](
restateClient,
"hydra.v1.YourService",
keyValue,
"YourOperation",
).Send(ctx, request)
invocation, err := s.yourServiceClient(keyValue).
YourOperation().
Send(ctx, &hydrav1.YourRequest{
KeyField: keyValue,
})
if err != nil {
return fmt.Errorf("failed to start: %w", err)
}
// Use invocation.Id for tracking
```

**Benefits:**

- Type-safe: Compile-time checking of requests/responses
- Discoverable: IDE autocomplete for all operations
- Cleaner: No manual service name strings or type parameters
- Maintainable: Refactors automatically when proto changes

## Best Practices

1. **Small Steps**: Break operations into focused, single-purpose durable steps
Expand Down
31 changes: 14 additions & 17 deletions go/apps/ctrl/services/deployment/create_deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"time"

"connectrpc.com/connect"
restateingress "github.com/restatedev/sdk-go/ingress"
ctrlv1 "github.com/unkeyed/unkey/go/gen/proto/ctrl/v1"
hydrav1 "github.com/unkeyed/unkey/go/gen/proto/hydra/v1"
"github.com/unkeyed/unkey/go/pkg/db"
Expand Down Expand Up @@ -134,23 +133,21 @@ func (s *Service) CreateDeployment(
if keyspaceID != "" {
keyAuthID = &keyspaceID
}
deployReq := &hydrav1.DeployRequest{
DeploymentId: deploymentID,
DockerImage: req.Msg.GetDockerImage(),
KeyAuthId: keyAuthID,
}
// this is ugly, but we're waiting for
// https://github.com/restatedev/sdk-go/issues/103
invocation := restateingress.WorkflowSend[*hydrav1.DeployRequest](
s.restate,
"hydra.v1.DeploymentService",
project.ID,
"Deploy",
).Send(ctx, deployReq)
if invocation.Error != nil {
s.logger.Error("failed to start deployment workflow", "error", invocation.Error.Error())
return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("unable to start workflow: %w", invocation.Error))

// Send deployment request asynchronously (fire-and-forget)
invocation, err := s.deploymentClient(project.ID).
Deploy().
Send(ctx, &hydrav1.DeployRequest{
DeploymentId: deploymentID,
DockerImage: req.Msg.GetDockerImage(),
KeyAuthId: keyAuthID,
})

if err != nil {
s.logger.Error("failed to start deployment workflow", "error", err)
return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("unable to start workflow: %w", err))
}

s.logger.Info("deployment workflow started",
"deployment_id", deploymentID,
"invocation_id", invocation.Id,
Expand Down
14 changes: 5 additions & 9 deletions go/apps/ctrl/services/deployment/promote.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"

"connectrpc.com/connect"
restateingress "github.com/restatedev/sdk-go/ingress"
ctrlv1 "github.com/unkeyed/unkey/go/gen/proto/ctrl/v1"
hydrav1 "github.com/unkeyed/unkey/go/gen/proto/hydra/v1"
"github.com/unkeyed/unkey/go/pkg/db"
Expand All @@ -32,14 +31,11 @@ func (s *Service) Promote(ctx context.Context, req *connect.Request[ctrlv1.Promo

// Call the Restate workflow using project ID as the key
// This ensures only one operation per project can run at a time
_, err = restateingress.Object[*hydrav1.PromoteRequest, *hydrav1.PromoteResponse](
s.restate,
"hydra.v1.DeploymentService",
targetDeployment.ProjectID,
"Promote",
).Request(ctx, &hydrav1.PromoteRequest{
TargetDeploymentId: req.Msg.GetTargetDeploymentId(),
})
_, err = s.deploymentClient(targetDeployment.ProjectID).
Promote().
Request(ctx, &hydrav1.PromoteRequest{
TargetDeploymentId: req.Msg.GetTargetDeploymentId(),
})

if err != nil {
s.logger.Error("promotion workflow failed",
Expand Down
17 changes: 6 additions & 11 deletions go/apps/ctrl/services/deployment/rollback.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"

"connectrpc.com/connect"
restateingress "github.com/restatedev/sdk-go/ingress"
ctrlv1 "github.com/unkeyed/unkey/go/gen/proto/ctrl/v1"
hydrav1 "github.com/unkeyed/unkey/go/gen/proto/hydra/v1"
"github.com/unkeyed/unkey/go/pkg/db"
Expand Down Expand Up @@ -34,16 +33,12 @@ func (s *Service) Rollback(ctx context.Context, req *connect.Request[ctrlv1.Roll

// Call the Restate workflow using project ID as the key
// This ensures only one rollback per project can run at a time
// Using Object for blocking/synchronous invocation
_, err = restateingress.Object[*hydrav1.RollbackRequest, *hydrav1.RollbackResponse](
s.restate,
"hydra.v1.DeploymentService",
sourceDeployment.ProjectID,
"Rollback",
).Request(ctx, &hydrav1.RollbackRequest{
SourceDeploymentId: req.Msg.GetSourceDeploymentId(),
TargetDeploymentId: req.Msg.GetTargetDeploymentId(),
})
_, err = s.deploymentClient(sourceDeployment.ProjectID).
Rollback().
Request(ctx, &hydrav1.RollbackRequest{
SourceDeploymentId: req.Msg.GetSourceDeploymentId(),
TargetDeploymentId: req.Msg.GetTargetDeploymentId(),
})

if err != nil {
s.logger.Error("rollback workflow failed",
Expand Down
7 changes: 7 additions & 0 deletions go/apps/ctrl/services/deployment/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package deployment
import (
restateingress "github.com/restatedev/sdk-go/ingress"
"github.com/unkeyed/unkey/go/gen/proto/ctrl/v1/ctrlv1connect"
hydrav1 "github.com/unkeyed/unkey/go/gen/proto/hydra/v1"
"github.com/unkeyed/unkey/go/pkg/db"
"github.com/unkeyed/unkey/go/pkg/otel/logging"
)
Expand All @@ -17,6 +18,12 @@ type Service struct {
logger logging.Logger
}

// deploymentClient creates a typed Restate ingress client for the DeploymentService
// keyed by the given project ID to ensure only one operation per project runs at a time.
func (s *Service) deploymentClient(projectID string) hydrav1.DeploymentServiceIngressClient {
return hydrav1.NewDeploymentServiceIngressClient(s.restate, projectID)
}

type Config struct {
Database db.Database
PartitionDB db.Database
Expand Down
30 changes: 30 additions & 0 deletions go/gen/proto/hydra/v1/certificate_restate.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 40 additions & 0 deletions go/gen/proto/hydra/v1/deployment_restate.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions go/gen/proto/hydra/v1/routing_restate.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ require (
github.com/pressly/goose/v3 v3.25.0
github.com/prometheus/client_golang v1.23.2
github.com/redis/go-redis/v9 v9.9.0
github.com/restatedev/sdk-go v0.21.0
github.com/shirou/gopsutil/v4 v4.25.7
github.com/spiffe/go-spiffe/v2 v2.6.0
github.com/sqlc-dev/plugin-sdk-go v1.23.0
Expand All @@ -50,7 +51,7 @@ require (
go.opentelemetry.io/otel/trace v1.38.0
golang.org/x/net v0.43.0
golang.org/x/text v0.29.0
google.golang.org/protobuf v1.36.8
google.golang.org/protobuf v1.36.10
k8s.io/api v0.34.1
k8s.io/apimachinery v0.34.1
k8s.io/client-go v0.34.1
Expand Down Expand Up @@ -262,7 +263,7 @@ require (
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/macabu/inamedparam v0.2.0 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/mailru/easyjson v0.9.1 // indirect
github.com/manuelarte/embeddedstructfieldcheck v0.3.0 // indirect
github.com/manuelarte/funcorder v0.5.0 // indirect
github.com/maratori/testableexamples v1.0.0 // indirect
Expand Down Expand Up @@ -322,7 +323,6 @@ require (
github.com/quic-go/quic-go v0.54.0 // indirect
github.com/raeperd/recvcheck v0.2.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/restatedev/sdk-go v0.20.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/riza-io/grpc-go v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
Expand Down
Loading
Loading