diff --git a/kernel/model/attribute_view.go b/kernel/model/attribute_view.go index c3a334e89..faf8fdcb2 100644 --- a/kernel/model/attribute_view.go +++ b/kernel/model/attribute_view.go @@ -3582,7 +3582,7 @@ func updateBoundBlockAvsAttribute(avIDs []string) { } func ReloadAttrView(avID string) { - task.AppendTaskWithDelay(task.ReloadAttributeView, 200*time.Millisecond, pushReloadAttrView, avID) + task.AppendAsyncTaskWithDelay(task.ReloadAttributeView, 200*time.Millisecond, pushReloadAttrView, avID) } diff --git a/kernel/model/bazzar.go b/kernel/model/bazzar.go index 0c9d0dfa2..99660c384 100644 --- a/kernel/model/bazzar.go +++ b/kernel/model/bazzar.go @@ -105,10 +105,7 @@ func BatchUpdateBazaarPackages(frontend string) { } util.ReloadUI() - go func() { - util.WaitForUILoaded() - task.AppendTaskWithDelay(task.PushMsg, 1*time.Second, util.PushMsg, fmt.Sprintf(Conf.language(237), total), 5000) - }() + task.AppendAsyncTaskWithDelay(task.PushMsg, 3*time.Second, util.PushMsg, fmt.Sprintf(Conf.language(237), total), 5000) return } diff --git a/kernel/model/cloud_service.go b/kernel/model/cloud_service.go index c4b6ab2b7..6623931c3 100644 --- a/kernel/model/cloud_service.go +++ b/kernel/model/cloud_service.go @@ -239,7 +239,7 @@ func refreshSubscriptionExpirationRemind() { now := time.Now().UnixMilli() if now >= expired { // 已经过期 if now-expired <= 1000*60*60*24*2 { // 2 天内提醒 https://github.com/siyuan-note/siyuan/issues/7816 - task.AppendTaskWithDelay(task.PushMsg, 30*time.Second, util.PushErrMsg, Conf.Language(128), 0) + task.AppendAsyncTaskWithDelay(task.PushMsg, 30*time.Second, util.PushErrMsg, Conf.Language(128), 0) } return } @@ -250,8 +250,7 @@ func refreshSubscriptionExpirationRemind() { } if 0 < remains && expireDay > remains { - util.WaitForUILoaded() - task.AppendTaskWithDelay(task.PushMsg, 7*time.Second, util.PushErrMsg, fmt.Sprintf(Conf.Language(127), remains), 0) + task.AppendAsyncTaskWithDelay(task.PushMsg, 7*time.Second, util.PushErrMsg, fmt.Sprintf(Conf.Language(127), remains), 0) return } } diff --git a/kernel/model/conf.go b/kernel/model/conf.go index 03c455f35..3c3add304 100644 --- a/kernel/model/conf.go +++ b/kernel/model/conf.go @@ -470,9 +470,9 @@ func InitConf() { go func() { util.WaitForUILoaded() if util.ContainerIOS == util.Container || util.ContainerAndroid == util.Container { - task.AppendTaskWithDelay(task.PushMsg, 2*time.Second, util.PushMsg, Conf.language(245), 15000) + task.AppendAsyncTaskWithDelay(task.PushMsg, 2*time.Second, util.PushMsg, Conf.language(245), 15000) } else { - task.AppendTaskWithDelay(task.PushMsg, 2*time.Second, util.PushMsg, Conf.language(244), 15000) + task.AppendAsyncTaskWithDelay(task.PushMsg, 2*time.Second, util.PushMsg, Conf.language(244), 15000) } }() } diff --git a/kernel/model/index_fix.go b/kernel/model/index_fix.go index 913acf16f..c769b72d1 100644 --- a/kernel/model/index_fix.go +++ b/kernel/model/index_fix.go @@ -256,10 +256,7 @@ func resetDuplicateBlocksOnFileSys() { if needRefreshUI { util.ReloadUI() - go func() { - util.WaitForUILoaded() - task.AppendTaskWithDelay(task.PushMsg, 3*time.Second, util.PushMsg, Conf.Language(190), 5000) - }() + task.AppendAsyncTaskWithDelay(task.PushMsg, 3*time.Second, util.PushMsg, Conf.Language(190), 5000) } } diff --git a/kernel/model/mount.go b/kernel/model/mount.go index e03092735..cc55d4543 100644 --- a/kernel/model/mount.go +++ b/kernel/model/mount.go @@ -219,7 +219,7 @@ func Mount(boxID string) (alreadyMount bool, err error) { Conf.Save() } - task.AppendTaskWithDelay(task.PushMsg, 3*time.Second, util.PushErrMsg, Conf.Language(52), 7000) + task.AppendAsyncTaskWithDelay(task.PushMsg, 3*time.Second, util.PushErrMsg, Conf.Language(52), 7000) go func() { // 每次打开帮助文档时自动检查版本更新并提醒 https://github.com/siyuan-note/siyuan/issues/5057 time.Sleep(time.Second * 10) diff --git a/kernel/model/repository.go b/kernel/model/repository.go index 0980bdb43..0115268f7 100644 --- a/kernel/model/repository.go +++ b/kernel/model/repository.go @@ -477,7 +477,7 @@ func ResetRepo() (err error) { Conf.Save() util.PushUpdateMsg(msgId, Conf.Language(145), 3000) - task.AppendTaskWithDelay(task.ReloadUI, 2*time.Second, util.ReloadUI) + task.AppendAsyncTaskWithDelay(task.ReloadUI, 2*time.Second, util.ReloadUI) return } @@ -656,10 +656,7 @@ func checkoutRepo(id string) { task.AppendTask(task.ReloadUI, util.ReloadUIResetScroll) if syncEnabled { - func() { - time.Sleep(5 * time.Second) - util.PushMsg(Conf.Language(134), 0) - }() + task.AppendAsyncTaskWithDelay(task.PushMsg, 3*time.Second, util.PushMsg, Conf.Language(134), 0) } return } diff --git a/kernel/task/queue.go b/kernel/task/queue.go index 5fc1173c7..e8a8cd7b2 100644 --- a/kernel/task/queue.go +++ b/kernel/task/queue.go @@ -19,6 +19,7 @@ package task import ( "context" "reflect" + "slices" "sync" "time" @@ -37,23 +38,24 @@ type Task struct { Handler reflect.Value Args []interface{} Created time.Time + Async bool // 为 true 说明是异步任务,不会阻塞任务队列,满足 Delay 条件后立即执行 Delay time.Duration Timeout time.Duration } func AppendTask(action string, handler interface{}, args ...interface{}) { - appendTaskWithDelayTimeout(action, 0, 24*time.Hour, handler, args...) + appendTaskWithDelayTimeout(action, false, 0, 24*time.Hour, handler, args...) } -func AppendTaskWithDelay(action string, delay time.Duration, handler interface{}, args ...interface{}) { - appendTaskWithDelayTimeout(action, delay, 24*time.Hour, handler, args...) +func AppendAsyncTaskWithDelay(action string, delay time.Duration, handler interface{}, args ...interface{}) { + appendTaskWithDelayTimeout(action, true, delay, 24*time.Hour, handler, args...) } func AppendTaskWithTimeout(action string, timeout time.Duration, handler interface{}, args ...interface{}) { - appendTaskWithDelayTimeout(action, 0, timeout, handler, args...) + appendTaskWithDelayTimeout(action, false, 0, timeout, handler, args...) } -func appendTaskWithDelayTimeout(action string, delay, timeout time.Duration, handler interface{}, args ...interface{}) { +func appendTaskWithDelayTimeout(action string, async bool, delay, timeout time.Duration, handler interface{}, args ...interface{}) { if util.IsExiting.Load() { //logging.LogWarnf("task queue is paused, action [%s] will be ignored", action) return @@ -64,6 +66,7 @@ func appendTaskWithDelayTimeout(action string, delay, timeout time.Duration, han Handler: reflect.ValueOf(handler), Args: args, Created: time.Now(), + Async: async, Delay: delay, Timeout: timeout, } @@ -175,13 +178,11 @@ func StatusJob() { if nil != actionLangs { if label := actionLangs[task.Action]; nil != label { action = label.(string) + } else { + continue } } - if "" == action { - continue - } - item := map[string]interface{}{"action": action} items = append(items, item) } @@ -204,8 +205,8 @@ func StatusJob() { } func ExecTaskJob() { - task := popTask() - if nil == task { + syncTask, asyncTasks := popTasks() + if nil == syncTask && 1 > len(asyncTasks) { return } @@ -213,10 +214,18 @@ func ExecTaskJob() { return } - execTask(task) + for _, asyncTask := range asyncTasks { + go func() { + execTask(asyncTask) + }() + } + + if nil != syncTask { + execTask(syncTask) + } } -func popTask() (ret *Task) { +func popTasks() (syncTask *Task, asyncTasks []*Task) { queueLock.Lock() defer queueLock.Unlock() @@ -224,12 +233,31 @@ func popTask() (ret *Task) { return } + var popedIndexes []int for i, task := range taskQueue { - if time.Since(task.Created) > task.Delay { - ret = task - taskQueue = append(taskQueue[:i], taskQueue[i+1:]...) - return + if time.Since(task.Created) <= task.Delay { + continue } + + if task.Async { + asyncTasks = append(asyncTasks, task) + popedIndexes = append(popedIndexes, i) + } else { + if nil == syncTask { + syncTask = task + popedIndexes = append(popedIndexes, i) + } + } + } + + if 0 < len(popedIndexes) { + var newQueue []*Task + for i, task := range taskQueue { + if !slices.Contains(popedIndexes, i) { + newQueue = append(newQueue, task) + } + } + taskQueue = newQueue } return } @@ -240,6 +268,10 @@ var ( ) func execTask(task *Task) { + if nil == task { + return + } + defer logging.Recover() args := make([]reflect.Value, len(task.Args)) @@ -251,9 +283,11 @@ func execTask(task *Task) { } } - currentTaskLock.Lock() - currentTask = task - currentTaskLock.Unlock() + if !task.Async { + currentTaskLock.Lock() + currentTask = task + currentTaskLock.Unlock() + } ctx, cancel := context.WithTimeout(context.Background(), task.Timeout) defer cancel() @@ -267,10 +301,12 @@ func execTask(task *Task) { case <-ctx.Done(): logging.LogWarnf("task [%s] timeout", task.Action) case <-ch: - //logging.LogInfof("task [%s] done", task.Action) + logging.LogInfof("task [%s] done", task.Action) } - currentTaskLock.Lock() - currentTask = nil - currentTaskLock.Unlock() + if !task.Async { + currentTaskLock.Lock() + currentTask = nil + currentTaskLock.Unlock() + } } diff --git a/kernel/util/runtime.go b/kernel/util/runtime.go index b96bb34ee..ca0d4d7c7 100644 --- a/kernel/util/runtime.go +++ b/kernel/util/runtime.go @@ -45,8 +45,13 @@ var UseSingleLineSave = true var IsUILoaded = false func WaitForUILoaded() { + start := time.Now() for !IsUILoaded { time.Sleep(200 * time.Millisecond) + if time.Since(start) > 30*time.Second { + logging.LogErrorf("wait for ui loaded timeout") + break + } } } diff --git a/kernel/util/websocket.go b/kernel/util/websocket.go index 7813f7976..51d58d7c8 100644 --- a/kernel/util/websocket.go +++ b/kernel/util/websocket.go @@ -153,23 +153,27 @@ func PushTxErr(msg string, code int, data interface{}) { } func PushUpdateMsg(msgId string, msg string, timeout int) { + WaitForUILoaded() BroadcastByType("main", "msg", 0, msg, map[string]interface{}{"id": msgId, "closeTimeout": timeout}) return } func PushMsg(msg string, timeout int) (msgId string) { + WaitForUILoaded() msgId = gulu.Rand.String(7) BroadcastByType("main", "msg", 0, msg, map[string]interface{}{"id": msgId, "closeTimeout": timeout}) return } func PushErrMsg(msg string, timeout int) (msgId string) { + WaitForUILoaded() msgId = gulu.Rand.String(7) BroadcastByType("main", "msg", -1, msg, map[string]interface{}{"id": msgId, "closeTimeout": timeout}) return } func PushStatusBar(msg string) { + WaitForUILoaded() msg += " (" + time.Now().Format("2006-01-02 15:04:05") + ")" BroadcastByType("main", "statusbar", 0, msg, nil) }