11import { NextRequest , NextResponse } from "next/server" ;
22import { db } from "@/db" ;
3- import { deployments , servers , services , rollouts } from "@/db/schema" ;
3+ import {
4+ deployments ,
5+ deploymentPorts ,
6+ servers ,
7+ services ,
8+ rollouts ,
9+ } from "@/db/schema" ;
410import { eq , and , inArray , isNotNull , isNull } from "drizzle-orm" ;
511import { verifyAgentRequest } from "@/lib/agent-auth" ;
612
@@ -24,6 +30,14 @@ type StatusReport = {
2430} ;
2531
2632async function checkRolloutProgress ( rolloutId : string ) : Promise < void > {
33+ const rollout = await db
34+ . select ( )
35+ . from ( rollouts )
36+ . where ( eq ( rollouts . id , rolloutId ) )
37+ . then ( ( r ) => r [ 0 ] ) ;
38+
39+ if ( ! rollout || rollout . status !== "in_progress" ) return ;
40+
2741 const rolloutDeployments = await db
2842 . select ( )
2943 . from ( deployments )
@@ -41,60 +55,99 @@ async function checkRolloutProgress(rolloutId: string): Promise<void> {
4155 const allHealthy = newDeployments . every ( ( d ) => d . status === "healthy" ) ;
4256
4357 if ( allHealthy ) {
44- console . log (
45- `[rollout:${ rolloutId } ] all healthy → running, completing rollout` ,
46- ) ;
58+ const serviceId = newDeployments [ 0 ] . serviceId ;
4759
48- await db
49- . update ( deployments )
50- . set ( { status : "running" } )
51- . where (
52- and (
53- eq ( deployments . rolloutId , rolloutId ) ,
54- eq ( deployments . status , "healthy" ) ,
55- ) ,
56- ) ;
57-
58- await db
60+ const updated = await db
5961 . update ( rollouts )
6062 . set ( {
6163 status : "completed" ,
6264 currentStage : "completed" ,
6365 completedAt : new Date ( ) ,
6466 } )
65- . where ( eq ( rollouts . id , rolloutId ) ) ;
67+ . where (
68+ and ( eq ( rollouts . id , rolloutId ) , eq ( rollouts . status , "in_progress" ) ) ,
69+ )
70+ . returning ( ) ;
71+
72+ if ( updated . length > 0 ) {
73+ console . log (
74+ `[rollout:${ rolloutId } ] all healthy → running, completing rollout` ,
75+ ) ;
76+
77+ await db
78+ . update ( deployments )
79+ . set ( { status : "stopping" } )
80+ . where (
81+ and (
82+ eq ( deployments . serviceId , serviceId ) ,
83+ eq ( deployments . status , "draining" ) ,
84+ ) ,
85+ ) ;
86+
87+ await db
88+ . update ( deployments )
89+ . set ( { status : "running" } )
90+ . where (
91+ and (
92+ eq ( deployments . rolloutId , rolloutId ) ,
93+ eq ( deployments . status , "healthy" ) ,
94+ ) ,
95+ ) ;
96+ }
6697 }
6798}
6899
69100async function handleRolloutFailure (
70101 rolloutId : string ,
71102 failedStage : string ,
72103) : Promise < void > {
73- await db
74- . update ( rollouts )
75- . set ( { status : "failed" , currentStage : failedStage } )
76- . where ( eq ( rollouts . id , rolloutId ) ) ;
77-
78104 const rolloutDeployments = await db
79105 . select ( )
80106 . from ( deployments )
81107 . where ( eq ( deployments . rolloutId , rolloutId ) ) ;
82108
83- const newDeployments = rolloutDeployments . filter (
84- ( d ) => d . status !== "running" && d . status !== "stopped" ,
85- ) ;
109+ if ( rolloutDeployments . length === 0 ) return ;
110+
111+ const serviceId = rolloutDeployments [ 0 ] . serviceId ;
86112
87- for ( const dep of newDeployments ) {
113+ const updated = await db
114+ . update ( rollouts )
115+ . set ( { status : "failed" , currentStage : failedStage } )
116+ . where ( and ( eq ( rollouts . id , rolloutId ) , eq ( rollouts . status , "in_progress" ) ) )
117+ . returning ( ) ;
118+
119+ if ( updated . length > 0 ) {
88120 await db
89121 . update ( deployments )
90- . set ( { status : "rolled_back" , failedStage : failedStage } )
91- . where ( eq ( deployments . id , dep . id ) ) ;
92- }
122+ . set ( { status : "running" } )
123+ . where (
124+ and (
125+ eq ( deployments . serviceId , serviceId ) ,
126+ eq ( deployments . status , "draining" ) ,
127+ ) ,
128+ ) ;
93129
94- await db
95- . update ( rollouts )
96- . set ( { status : "rolled_back" , completedAt : new Date ( ) } )
97- . where ( eq ( rollouts . id , rolloutId ) ) ;
130+ await db
131+ . update ( deployments )
132+ . set ( { status : "rolled_back" , failedStage } )
133+ . where (
134+ and (
135+ eq ( deployments . rolloutId , rolloutId ) ,
136+ inArray ( deployments . status , [
137+ "pending" ,
138+ "pulling" ,
139+ "starting" ,
140+ "healthy" ,
141+ "failed" ,
142+ ] ) ,
143+ ) ,
144+ ) ;
145+
146+ await db
147+ . update ( rollouts )
148+ . set ( { status : "rolled_back" , completedAt : new Date ( ) } )
149+ . where ( eq ( rollouts . id , rolloutId ) ) ;
150+ }
98151}
99152
100153export async function POST ( request : NextRequest ) {
@@ -184,12 +237,12 @@ export async function POST(request: NextRequest) {
184237 if ( ! reportedDeploymentIds . includes ( dep . id ) ) {
185238 if ( dep . status === "stopping" ) {
186239 console . log (
187- `[status:${ serverId . slice ( 0 , 8 ) } ] deployment ${ dep . id . slice ( 0 , 8 ) } was stopping and container gone, marking STOPPED ` ,
240+ `[status:${ serverId . slice ( 0 , 8 ) } ] deployment ${ dep . id . slice ( 0 , 8 ) } was stopping and container gone, deleting ` ,
188241 ) ;
189242 await db
190- . update ( deployments )
191- . set ( { status : "stopped" , healthStatus : null , containerId : null } )
192- . where ( eq ( deployments . id , dep . id ) ) ;
243+ . delete ( deploymentPorts )
244+ . where ( eq ( deploymentPorts . deploymentId , dep . id ) ) ;
245+ await db . delete ( deployments ) . where ( eq ( deployments . id , dep . id ) ) ;
193246 } else {
194247 console . log (
195248 `[status:${ serverId . slice ( 0 , 8 ) } ] deployment ${ dep . id . slice ( 0 , 8 ) } NOT reported, marking UNKNOWN` ,
0 commit comments