From 9aaa308ca2608cdd5240ba9506f94f68649ed77d Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 28 Feb 2026 23:46:16 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=B8=80=E4=B8=AA=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=84=9A=E6=9C=AC=E4=BB=BB=E5=8A=A1=EF=BC=9A=E6=AF=8F?= =?UTF-8?q?=E6=99=9A=E4=B9=9D=E7=82=B9=E8=87=AA=E5=8A=A8=E5=8F=96=E6=B6=88?= =?UTF-8?q?=E5=BD=93=E5=A4=A9=E9=A2=84=E7=BA=A6=E4=BD=86=E6=98=AF=E6=B2=A1?= =?UTF-8?q?=E4=BA=BA=E5=8E=BB=E4=BF=AE=E7=9A=84=E5=8D=95=E5=AD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/src/cmd/wts-server/main.go | 7 +- back/src/daemon/entry.go | 1 + back/src/daemon/scheduledAutoCancel.go | 117 +++++++++++++++++++++++++ back/src/daemon/signalHandler.go | 2 + 4 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 back/src/daemon/scheduledAutoCancel.go diff --git a/back/src/cmd/wts-server/main.go b/back/src/cmd/wts-server/main.go index 821eeb2..eccb887 100644 --- a/back/src/cmd/wts-server/main.go +++ b/back/src/cmd/wts-server/main.go @@ -25,11 +25,12 @@ func main() { //设置微信SDK wx := wechat.Setup(cfg) - //启动守护进程 - daemon.Setup() - //然后,启动服务器 app := server.Setup(cfg, dbx, wx) + + //启动守护进程(因为有的服务需要用到上下文,所以现在修改在server.Setup被执行的后面启动) + daemon.Setup() + err := app.Start("127.0.0.1:" + strconv.Itoa(cfg.ListenPort)) println("Server exited." + err.Error()) diff --git a/back/src/daemon/entry.go b/back/src/daemon/entry.go index 5476705..76b5e2c 100644 --- a/back/src/daemon/entry.go +++ b/back/src/daemon/entry.go @@ -2,4 +2,5 @@ package daemon func Setup() { regExitSigs() + scheduledAutoCancel() } diff --git a/back/src/daemon/scheduledAutoCancel.go b/back/src/daemon/scheduledAutoCancel.go new file mode 100644 index 0000000..65b5324 --- /dev/null +++ b/back/src/daemon/scheduledAutoCancel.go @@ -0,0 +1,117 @@ +package daemon + +import ( + "context" + "fmt" + "log/slog" + "time" + + "github.com/jackc/pgx/v5/pgtype" + "zsxyww.com/wts/model" + "zsxyww.com/wts/model/sqlc" + "zsxyww.com/wts/server" + + "math/rand" +) + +// 在每天值班结束的时候,自动取消(改日修)预约在今天但是状态今天没有更新的工单 +func scheduledAutoCancel() { + go func() { + var first = true + var duration time.Duration + var jobID int + for { + jobID = rand.Int() + //暂时在每晚的9点执行逻辑 + now := time.Now() + next := time.Date(now.Year(), now.Month(), now.Day(), 21, 0, 0, 0, now.Location()) + + // 如果程序启动时已经过了9点,那么就立即执行 + if (!now.Before(next)) && (first == true) { + first = false + goto do + } + + // 如果当前时间已经过了9点,比如程序执行完上一次了,就设置为明天9点的定时 + if !now.Before(next) { + next = next.AddDate(0, 0, 1) + } + first = false //这里防止程序在9点前启动的时候会跑两次逻辑... + + duration = next.Sub(now) + slog.Info("下一次取消程序安排上了", "duration", duration, "nextTime", next) + time.Sleep(duration) + + // 醒来后执行取消工单的操作 + do: + if err := doCancelJob(jobID); err != nil { + slog.Error("自动预约处理程序执行失败", "error", err, "ID", jobID) + } else { + slog.Info("自动取消程序执行完毕", "ID", jobID) + } + } + }() + +} + +func doCancelJob(jobID int) error { + slog.Info("开始执行每日预约处理程序", "ID", jobID) + ctx := context.Background() + err := server.DB.DoQuery(context.Background(), "system", func(q *sqlc.Queries) error { + //1.获取今日(实际上获取所有过去的预约单来保险)预约 + allZone, _ := model.BlocksInZone("all") + var beforeScheduledTickets = []sqlc.WtsVTicket{} + t, err := q.FilterTickets(ctx, sqlc.FilterTicketsParams{ + Blocks: allZone, + Status: []sqlc.WtsStatus{"scheduled"}, + }) + if err != nil { + return fmt.Errorf("在获取工单时失败了:%w", err) + } + for _, a := range t { + now := time.Now() + + var date time.Time + if a.AppointedAt.Valid { + date = a.AppointedAt.Time + } else { + continue + } + + if date.Before(now) { + beforeScheduledTickets = append(beforeScheduledTickets, a) + } + } + //2.将所有工单改为“已取消” + var ticketIDSlice []int32 + for _, a := range beforeScheduledTickets { + ticketIDSlice = append(ticketIDSlice, a.Tid) + } + slog.Info("本次操作共涉及如下工单", "t", ticketIDSlice) + for _, a := range ticketIDSlice { + _, err := q.CreateTicketTrace(ctx, sqlc.CreateTicketTraceParams{ + Tid: a, + UpdatedAt: pgtype.Timestamptz{ + Time: time.Now(), + Valid: true, + }, + Op: "-1", + NewStatus: sqlc.NullWtsStatus{ + WtsStatus: "canceled", + Valid: true, + }, + NewPriority: sqlc.NullWtsPriority{ + WtsPriority: "mainline", + Valid: true, + }, + Remark: "系统检测到预约已过期,似乎是我们爽约了,我们非常抱歉为您造成的不便,您可以再次提交报修预约,我们会努力做得更好。", + }) + if err != nil { + return fmt.Errorf("在增加记录时失败了:%w", err) + } + } + //3.如果没有问题就提交事务 + return nil + }) + return err +} diff --git a/back/src/daemon/signalHandler.go b/back/src/daemon/signalHandler.go index dd1ca54..c35daae 100644 --- a/back/src/daemon/signalHandler.go +++ b/back/src/daemon/signalHandler.go @@ -2,6 +2,7 @@ package daemon import ( "fmt" + "log/slog" "os" "os/signal" "syscall" @@ -21,6 +22,7 @@ func regExitSigs() { go func() { sig := <-sigs + slog.Info("收到退出信号", "signal", sig) fmt.Printf("\n===== %s,roger that! =====\n", sig) err := runCleanup()