@@ -61,6 +61,8 @@ type QueueEntry = {
6161 resolve : ( value : unknown ) => void ;
6262 reject : ( reason ?: unknown ) => void ;
6363 enqueuedAt : number ;
64+ sequence : number ;
65+ priority : number ;
6466 warnAfterMs : number ;
6567 taskTimeoutMs ?: number ;
6668 taskTimeoutProgressAtMs ?: ( ) => number | undefined ;
@@ -107,6 +109,7 @@ function getQueueState() {
107109 lanes : new Map < string , LaneState > ( ) ,
108110 activeTaskWaiters : new Set < ActiveTaskWaiter > ( ) ,
109111 nextTaskId : 1 ,
112+ nextQueueSequence : 1 ,
110113 } ) ) ;
111114 // Schema migration: the singleton may have been created by an older code
112115 // version (e.g. v2026.4.2) that did not include `activeTaskWaiters`. After
@@ -117,6 +120,27 @@ function getQueueState() {
117120 if ( ! state . activeTaskWaiters ) {
118121 state . activeTaskWaiters = new Set < ActiveTaskWaiter > ( ) ;
119122 }
123+ if ( ! state . nextQueueSequence ) {
124+ state . nextQueueSequence = 1 ;
125+ }
126+ let maxQueueSequence = state . nextQueueSequence - 1 ;
127+ for ( const lane of state . lanes . values ( ) ) {
128+ for ( const entry of lane . queue as Array <
129+ QueueEntry & { priority ?: number ; sequence ?: number }
130+ > ) {
131+ if ( typeof entry . priority !== "number" ) {
132+ entry . priority = 0 ;
133+ }
134+ if ( typeof entry . sequence !== "number" ) {
135+ entry . sequence = state . nextQueueSequence ++ ;
136+ } else {
137+ maxQueueSequence = Math . max ( maxQueueSequence , entry . sequence ) ;
138+ }
139+ }
140+ }
141+ if ( state . nextQueueSequence <= maxQueueSequence ) {
142+ state . nextQueueSequence = maxQueueSequence + 1 ;
143+ }
120144 return state ;
121145}
122146
@@ -204,6 +228,30 @@ function normalizeTaskTimeoutMs(value: number | undefined): number | undefined {
204228 return Math . max ( 1 , Math . floor ( value ) ) ;
205229}
206230
231+ function resolveQueuePriority ( priority : CommandQueueEnqueueOptions [ "priority" ] ) : number {
232+ switch ( priority ) {
233+ case "foreground" :
234+ return 1 ;
235+ case "background" :
236+ return - 1 ;
237+ default :
238+ return 0 ;
239+ }
240+ }
241+
242+ function enqueueLaneEntry ( state : LaneState , entry : QueueEntry ) : void {
243+ const insertAt = state . queue . findIndex (
244+ ( queued ) =>
245+ queued . priority < entry . priority ||
246+ ( queued . priority === entry . priority && queued . sequence > entry . sequence ) ,
247+ ) ;
248+ if ( insertAt < 0 ) {
249+ state . queue . push ( entry ) ;
250+ return ;
251+ }
252+ state . queue . splice ( insertAt , 0 , entry ) ;
253+ }
254+
207255async function runQueueEntryTask ( lane : string , entry : QueueEntry ) : Promise < unknown > {
208256 const taskPromise = Promise . resolve ( ) . then ( entry . task ) ;
209257 const taskTimeoutMs = normalizeTaskTimeoutMs ( entry . taskTimeoutMs ) ;
@@ -362,11 +410,13 @@ export function enqueueCommandInLane<T>(
362410 const warnAfterMs = opts ?. warnAfterMs ?? 2_000 ;
363411 const state = getLaneState ( cleaned ) ;
364412 return new Promise < T > ( ( resolve , reject ) => {
365- state . queue . push ( {
413+ enqueueLaneEntry ( state , {
366414 task : ( ) => task ( ) ,
367415 resolve : ( value ) => resolve ( value as T ) ,
368416 reject,
369417 enqueuedAt : Date . now ( ) ,
418+ sequence : queueState . nextQueueSequence ++ ,
419+ priority : resolveQueuePriority ( opts ?. priority ) ,
370420 warnAfterMs,
371421 taskTimeoutMs : normalizeTaskTimeoutMs ( opts ?. taskTimeoutMs ) ,
372422 taskTimeoutProgressAtMs : opts ?. taskTimeoutProgressAtMs ,
@@ -472,6 +522,7 @@ export function resetCommandQueueStateForTest(): void {
472522 resolveActiveTaskWaiter ( waiter , { drained : true } ) ;
473523 }
474524 queueState . nextTaskId = 1 ;
525+ queueState . nextQueueSequence = 1 ;
475526}
476527
477528/**
0 commit comments