@@ -16,6 +16,7 @@ var ErrCommandDoneOnce = fmt.Errorf("command is already done and has run mode on
1616
1717type AddItemOptions struct {
1818 Remember bool
19+ Wait bool
1920 RunAfterExecution func ()
2021}
2122
@@ -40,8 +41,8 @@ func NewQueueManager(
4041 scrollService : scrollService ,
4142 processLauncher : processLauncher ,
4243 commandQueue : make (map [string ]* domain.QueueItem ),
43- taskChan : make (chan string ),
44- taskDoneChan : make (chan struct {}),
44+ taskChan : make (chan string , 100 ), // FIXED: Buffered channel
45+ taskDoneChan : make (chan struct {}, 1 ), // FIXED: Buffered channel
4546 shutdownChan : make (chan struct {}),
4647 notifierChan : make ([]chan []string , 0 ),
4748 callbacksPostRun : make (map [string ]func ()),
@@ -66,15 +67,20 @@ func (sc *QueueManager) workItem(cmd string) error {
6667}
6768
6869func (sc * QueueManager ) notify () {
70+ sc .mu .Lock ()
6971 queuedCommands := make ([]string , 0 )
7072
71- for cmd , _ := range sc .commandQueue {
72- if sc . getStatus ( cmd ) != domain .ScrollLockStatusDone && sc . getStatus ( cmd ) != domain .ScrollLockStatusError {
73+ for cmd , item := range sc .commandQueue {
74+ if item . Status != domain .ScrollLockStatusDone && item . Status != domain .ScrollLockStatusError {
7375 queuedCommands = append (queuedCommands , cmd )
7476 }
7577 }
7678
77- for _ , notifier := range sc .notifierChan {
79+ notifiers := make ([]chan []string , len (sc .notifierChan ))
80+ copy (notifiers , sc .notifierChan )
81+ sc .mu .Unlock ()
82+
83+ for _ , notifier := range notifiers {
7884 select {
7985 case notifier <- queuedCommands :
8086 // Successfully sent queuedCommands to the notifier channel
@@ -111,9 +117,15 @@ func (sc *QueueManager) AddItemWithCallback(cmd string, cb func()) error {
111117 })
112118}
113119
120+ func (sc * QueueManager ) AddTempItemWithWait (cmd string ) error {
121+ return sc .addQueueItem (cmd , AddItemOptions {
122+ Remember : false ,
123+ Wait : true ,
124+ })
125+ }
126+
114127func (sc * QueueManager ) addQueueItem (cmd string , options AddItemOptions ) error {
115128 sc .mu .Lock ()
116- defer sc .mu .Unlock ()
117129
118130 setLock := options .Remember
119131
@@ -124,6 +136,7 @@ func (sc *QueueManager) addQueueItem(cmd string, options AddItemOptions) error {
124136 command , err := sc .scrollService .GetCommand (cmd )
125137
126138 if err != nil {
139+ sc .mu .Unlock ()
127140 return err
128141 }
129142
@@ -135,17 +148,25 @@ func (sc *QueueManager) addQueueItem(cmd string, options AddItemOptions) error {
135148 if value , ok := sc .commandQueue [cmd ]; ok {
136149
137150 if value .Status != domain .ScrollLockStatusDone && value .Status != domain .ScrollLockStatusError {
151+ sc .mu .Unlock ()
138152 return ErrAlreadyInQueue
139153 }
140154
141155 if value .Status == domain .ScrollLockStatusDone && command .Run == domain .RunModeOnce {
156+ sc .mu .Unlock ()
142157 return ErrCommandDoneOnce
143158 }
144159 }
145160
161+ var doneChan chan struct {}
162+ if options .Wait {
163+ doneChan = make (chan struct {})
164+ }
165+
146166 item := & domain.QueueItem {
147167 Status : domain .ScrollLockStatusWaiting ,
148168 UpdateLockStatus : setLock ,
169+ DoneChan : doneChan ,
149170 }
150171
151172 if options .RunAfterExecution != nil {
@@ -157,12 +178,27 @@ func (sc *QueueManager) addQueueItem(cmd string, options AddItemOptions) error {
157178 if setLock {
158179 lock , err := sc .scrollService .GetLock ()
159180 if err != nil {
181+ sc .mu .Unlock ()
160182 return err
161183 }
162184 lock .SetStatus (cmd , domain .ScrollLockStatusWaiting , nil )
163185 }
186+
187+ sc .mu .Unlock ()
188+
189+ // FIXED: Non-blocking send to buffered channel
164190 sc .taskChan <- cmd
165191
192+ // Wait for completion if requested
193+ if options .Wait {
194+ <- doneChan
195+ // Return error if command failed
196+ item := sc .GetQueueItem (cmd )
197+ if item != nil && item .Error != nil {
198+ return item .Error
199+ }
200+ }
201+
166202 return nil
167203}
168204
@@ -303,13 +339,19 @@ func (sc *QueueManager) RunQueue() {
303339 logger .Log ().Info ("Running command" , zap .String ("command" , cmd ))
304340 go func (c string , i * domain.QueueItem ) {
305341 defer func () {
342+ // Signal completion if someone is waiting
343+ if i .DoneChan != nil {
344+ close (i .DoneChan )
345+ }
346+
306347 if i .RunAfterExecution != nil {
307348 i .RunAfterExecution ()
308349 }
309350 if callback , ok := sc .callbacksPostRun [c ]; ok && callback != nil {
310351 callback ()
311352 }
312353
354+ // FIXED: Non-blocking send to buffered channel
313355 sc .taskDoneChan <- struct {}{}
314356 }()
315357 err := sc .workItem (c )
@@ -340,33 +382,30 @@ func (sc *QueueManager) Shutdown() {
340382}
341383
342384func (sc * QueueManager ) WaitUntilEmpty () {
343- notifier := make (chan []string )
385+ notifier := make (chan []string , 10 ) // FIXED: Buffered channel
386+
387+ sc .mu .Lock ()
344388 sc .notifierChan = append (sc .notifierChan , notifier )
345- println ("WaitUntilEmpty" )
346- for k , n := range sc .commandQueue {
347- if n .Status == domain .ScrollLockStatusError {
348- println (k + "---: " + string (n .Status ) + " " + n .Error .Error ())
349- } else {
350- println (k + "---: " + string (n .Status ))
351- }
352- }
389+ sc .mu .Unlock ()
390+
353391 for {
392+ sc .mu .Lock ()
393+ for cmd , item := range sc .commandQueue {
394+ println (cmd + ": " + string (item .Status ))
395+ }
396+ sc .mu .Unlock ()
397+
354398 cmds := <- notifier
355399 if len (cmds ) == 0 {
356400 // remove notifier
401+ sc .mu .Lock ()
357402 for i , n := range sc .notifierChan {
358403 if n == notifier {
359404 sc .notifierChan = append (sc .notifierChan [:i ], sc .notifierChan [i + 1 :]... )
360405 break
361406 }
362407 }
363- for k , n := range sc .commandQueue {
364- if n .Status == domain .ScrollLockStatusError {
365- println (k + ": " + string (n .Status ) + " " + n .Error .Error ())
366- } else {
367- println (k + ": " + string (n .Status ))
368- }
369- }
408+ sc .mu .Unlock ()
370409 return
371410 }
372411 }
0 commit comments