package ports import ( "context" "fmt" ) // StopReason classifies why Lobby asks Runtime Manager to stop a game // container. The enum is part of the `runtime:stop_jobs` envelope and // mirrors the AsyncAPI contract frozen in // `rtmanager/api/runtime-jobs-asyncapi.yaml`. // // Lobby v1 produces only StopReasonOrphanCleanup (orphan-container path // in the runtime-job-result worker) and StopReasonCancelled // (user-lifecycle cascade). The remaining values are reserved in the // shared contract for future producers (Game Master, Admin Service, // enrollment automation). type StopReason string // StopReason enum values. The set is fixed by // `rtmanager/api/runtime-jobs-asyncapi.yaml`; adding a new value is a // contract bump that must be coordinated across producers and consumers. const ( // StopReasonOrphanCleanup releases a container whose post-start // metadata persistence failed in Lobby. StopReasonOrphanCleanup StopReason = "orphan_cleanup" // StopReasonCancelled covers user-lifecycle cascade and explicit // cancel paths for in-flight games. StopReasonCancelled StopReason = "cancelled" // StopReasonFinished is reserved for engine-driven game finish // flows; not produced by Lobby in v1. StopReasonFinished StopReason = "finished" // StopReasonAdminRequest is reserved for future admin-initiated // stop paths through Lobby; not produced by Lobby in v1. StopReasonAdminRequest StopReason = "admin_request" // StopReasonTimeout is reserved for future enrollment-timeout-driven // stop paths; not produced by Lobby in v1. StopReasonTimeout StopReason = "timeout" ) // String returns reason as its stored enum value. func (reason StopReason) String() string { return string(reason) } // Validate reports whether reason carries one of the five values fixed // by the AsyncAPI contract. func (reason StopReason) Validate() error { switch reason { case StopReasonOrphanCleanup, StopReasonCancelled, StopReasonFinished, StopReasonAdminRequest, StopReasonTimeout: return nil case "": return fmt.Errorf("stop reason must not be empty") default: return fmt.Errorf("stop reason %q is not a recognised value", string(reason)) } } //go:generate go run go.uber.org/mock/mockgen -destination=../adapters/mocks/mock_runtimemanager.go -package=mocks galaxy/lobby/internal/ports RuntimeManager // RuntimeManager publishes runtime jobs to Runtime Manager via Redis // Streams. Lobby is the producer for both the start and the stop stream; // Runtime Manager (Stages 13+) is the eventual consumer. // // Image-reference resolution is intentionally a Lobby concern: each // game's `target_engine_version` is substituted into // `LOBBY_ENGINE_IMAGE_TEMPLATE` and the resulting `image_ref` is handed // to Runtime Manager verbatim on the start envelope. Runtime Manager // never resolves engine versions itself. type RuntimeManager interface { // PublishStartJob enqueues one start job for gameID with the // producer-resolved imageRef. Implementations must produce one // event in the configured runtime start jobs stream per call. A // zero-error return means the event is durably accepted into the // stream (Redis XADD succeeded); it does not imply that the // container has started. PublishStartJob(ctx context.Context, gameID, imageRef string) error // PublishStopJob enqueues one stop job for gameID with the // classifying reason. Implementations must produce one event in the // configured runtime stop jobs stream per call. The same durability // semantics as PublishStartJob apply. PublishStopJob(ctx context.Context, gameID string, reason StopReason) error }