feat: runtime manager
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package ports
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// JobResultPublisher emits one entry on the `runtime:job_results` Redis
|
||||
// Stream per finalised start or stop runtime job. Adapters serialise
|
||||
// every JobResult field verbatim so consumers (Game Lobby's
|
||||
// runtime-job-result worker today, future services tomorrow) see the
|
||||
// AsyncAPI shape frozen in `rtmanager/api/runtime-jobs-asyncapi.yaml`.
|
||||
//
|
||||
// The start-jobs and stop-jobs consumers publish through this port.
|
||||
// The synchronous REST handlers do not — REST callers receive the same
|
||||
// `Result` shape directly from the service layer.
|
||||
type JobResultPublisher interface {
|
||||
// Publish records result on the configured `runtime:job_results`
|
||||
// stream. A non-nil error reports a transport or serialisation
|
||||
// failure; the caller treats the failure as a degraded emission
|
||||
// (the operation_log already records the durable outcome).
|
||||
Publish(ctx context.Context, result JobResult) error
|
||||
}
|
||||
|
||||
// JobResult outcome values frozen by the
|
||||
// `RuntimeJobResultPayload.outcome` enum.
|
||||
const (
|
||||
// JobOutcomeSuccess marks a successful start or stop, including the
|
||||
// idempotent replay variant (`error_code=replay_no_op`).
|
||||
JobOutcomeSuccess = "success"
|
||||
|
||||
// JobOutcomeFailure marks a stable failure for which the payload
|
||||
// carries a non-empty `error_code`.
|
||||
JobOutcomeFailure = "failure"
|
||||
)
|
||||
|
||||
// JobResult carries the wire payload published on
|
||||
// `runtime:job_results`. The fields mirror the AsyncAPI schema frozen
|
||||
// in `rtmanager/api/runtime-jobs-asyncapi.yaml`; adapters serialise
|
||||
// every field verbatim so consumers see the contracted shape. Fields
|
||||
// that are required by the contract (every field on this struct) are
|
||||
// always present in the wire entry — even when their string value is
|
||||
// empty (allowed for `container_id` / `engine_endpoint` / `error_code`
|
||||
// / `error_message` on appropriate variants).
|
||||
type JobResult struct {
|
||||
// GameID identifies the platform game the job acted on. Required.
|
||||
GameID string
|
||||
|
||||
// Outcome reports the high-level outcome. Must be `success` or
|
||||
// `failure` (use the JobOutcome* constants).
|
||||
Outcome string
|
||||
|
||||
// ContainerID stores the Docker container id. Populated on
|
||||
// `success` for fresh starts and replays; empty on `failure` and
|
||||
// on `success/replay_no_op` for stop jobs that observed a removed
|
||||
// record.
|
||||
ContainerID string
|
||||
|
||||
// EngineEndpoint stores the stable engine URL
|
||||
// `http://galaxy-game-{game_id}:8080`. Populated alongside
|
||||
// ContainerID, empty in the same cases.
|
||||
EngineEndpoint string
|
||||
|
||||
// ErrorCode stores the stable error code from
|
||||
// `rtmanager/README.md §Error Model`. Empty for fresh successes,
|
||||
// `replay_no_op` for idempotent replays, one of the failure
|
||||
// codes otherwise.
|
||||
ErrorCode string
|
||||
|
||||
// ErrorMessage stores the operator-readable detail. Empty for
|
||||
// successes; populated alongside ErrorCode on failure.
|
||||
ErrorMessage string
|
||||
}
|
||||
|
||||
// Validate reports whether result satisfies the structural invariants
|
||||
// implied by the AsyncAPI schema: a non-empty game id and one of the
|
||||
// two known outcome values. The remaining fields are required to be
|
||||
// present on the wire but may be empty strings, so Validate does not
|
||||
// constrain them.
|
||||
func (result JobResult) Validate() error {
|
||||
if strings.TrimSpace(result.GameID) == "" {
|
||||
return fmt.Errorf("job result: game id must not be empty")
|
||||
}
|
||||
switch result.Outcome {
|
||||
case JobOutcomeSuccess, JobOutcomeFailure:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("job result: outcome %q is unsupported", result.Outcome)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user