@@ -49,6 +49,7 @@ export function createInMemorySandboxRepo(): SandboxRepoApi {
4949 const row : SandboxRow = {
5050 id : params . id ,
5151 orgId : params . orgId ,
52+ nodeId : null ,
5253 imageId : params . imageId ,
5354 profileId : params . profileId ,
5455 profileName : params . profileName ,
@@ -59,6 +60,7 @@ export function createInMemorySandboxRepo(): SandboxRepoApi {
5960 forkCount : 0 ,
6061 ttlSeconds : params . ttlSeconds ,
6162 failureReason : null ,
63+ lastActivityAt : null ,
6264 createdAt : now ,
6365 updatedAt : now ,
6466 startedAt : null ,
@@ -149,6 +151,7 @@ export function createInMemorySandboxRepo(): SandboxRepoApi {
149151 const row : SandboxRow = {
150152 id : params . id ,
151153 orgId : params . orgId ,
154+ nodeId : params . source . nodeId ,
152155 imageId : params . source . imageId ,
153156 profileId : params . source . profileId ,
154157 profileName : params . source . profileName ,
@@ -159,6 +162,7 @@ export function createInMemorySandboxRepo(): SandboxRepoApi {
159162 forkCount : 0 ,
160163 ttlSeconds : params . ttlSeconds ,
161164 failureReason : null ,
165+ lastActivityAt : now ,
162166 createdAt : now ,
163167 updatedAt : now ,
164168 startedAt : now ,
@@ -211,6 +215,51 @@ export function createInMemorySandboxRepo(): SandboxRepoApi {
211215
212216 return result
213217 } ) ,
218+
219+ findExpiredTtl : ( ) =>
220+ Effect . sync ( ( ) => {
221+ const now = Date . now ( )
222+ return Array . from ( store . values ( ) ) . filter ( ( r ) => {
223+ if ( r . status !== 'running' || ! r . startedAt ) return false
224+ return r . startedAt . getTime ( ) + r . ttlSeconds * 1000 < now
225+ } )
226+ } ) ,
227+
228+ findIdleSince : ( cutoff ) =>
229+ Effect . sync ( ( ) =>
230+ Array . from ( store . values ( ) ) . filter ( ( r ) => {
231+ if ( r . status !== 'running' ) return false
232+ const activity = r . lastActivityAt ?? r . startedAt ?? r . createdAt
233+ return activity . getTime ( ) < cutoff . getTime ( )
234+ } ) ,
235+ ) ,
236+
237+ findQueuedBefore : ( cutoff ) =>
238+ Effect . sync ( ( ) =>
239+ Array . from ( store . values ( ) ) . filter (
240+ ( r ) => r . status === 'queued' && r . createdAt . getTime ( ) < cutoff . getTime ( ) ,
241+ ) ,
242+ ) ,
243+
244+ getActiveNodeIds : ( ) =>
245+ Effect . sync ( ( ) => {
246+ const nodeIds = new Map < string , Uint8Array > ( )
247+ for ( const row of store . values ( ) ) {
248+ if ( row . status === 'running' && row . nodeId ) {
249+ nodeIds . set ( base62Encode ( row . nodeId ) , row . nodeId )
250+ }
251+ }
252+ return Array . from ( nodeIds . values ( ) )
253+ } ) ,
254+
255+ findRunningOnNodes : ( nodeIds ) =>
256+ Effect . sync ( ( ) => {
257+ if ( nodeIds . length === 0 ) return [ ]
258+ return Array . from ( store . values ( ) ) . filter ( ( r ) => {
259+ if ( r . status !== 'running' || ! r . nodeId ) return false
260+ return nodeIds . some ( ( nid ) => bytesEqual ( r . nodeId ! , nid ) )
261+ } )
262+ } ) ,
214263 }
215264}
216265
0 commit comments