Переглянути джерело

:recycle: Implement some delayed kernel events using task queues https://github.com/siyuan-note/siyuan/issues/12393

Daniel 10 місяців тому
батько
коміт
09eec52a02

+ 1 - 1
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)
 
 }
 

+ 1 - 4
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
 }
 

+ 2 - 3
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
 		}
 	}

+ 2 - 2
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)
 			}
 		}()
 	}

+ 1 - 4
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)
 	}
 }
 

+ 1 - 1
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)

+ 2 - 5
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
 }

+ 60 - 24
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,13 +233,32 @@ 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()
+	}
 }

+ 5 - 0
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
+		}
 	}
 }
 

+ 4 - 0
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)
 }