task调度器该用ants线程池
This commit is contained in:
@@ -10,3 +10,4 @@
|
|||||||
3. ListenHandler 的实现遇到问题只能panic, 没有处理错误
|
3. ListenHandler 的实现遇到问题只能panic, 没有处理错误
|
||||||
4. 暂时不考虑和区域主控间的同步消息, 假设所有消息都是异步的, 这可能导致无法知道指令是否执行成功
|
4. 暂时不考虑和区域主控间的同步消息, 假设所有消息都是异步的, 这可能导致无法知道指令是否执行成功
|
||||||
5. 如果系统停机时间很长, 待执行任务表中的任务过期了怎么办, 目前没有任务过期机制
|
5. 如果系统停机时间很长, 待执行任务表中的任务过期了怎么办, 目前没有任务过期机制
|
||||||
|
6. Task不支持插队
|
||||||
|
|||||||
17
go.mod
17
go.mod
@@ -5,21 +5,19 @@ go 1.25
|
|||||||
require (
|
require (
|
||||||
github.com/gin-gonic/gin v1.10.1
|
github.com/gin-gonic/gin v1.10.1
|
||||||
github.com/go-openapi/errors v0.22.2
|
github.com/go-openapi/errors v0.22.2
|
||||||
github.com/go-openapi/loads v0.22.0
|
|
||||||
github.com/go-openapi/runtime v0.28.0
|
github.com/go-openapi/runtime v0.28.0
|
||||||
github.com/go-openapi/spec v0.21.0
|
|
||||||
github.com/go-openapi/strfmt v0.23.0
|
github.com/go-openapi/strfmt v0.23.0
|
||||||
github.com/go-openapi/swag v0.23.0
|
github.com/go-openapi/swag v0.23.0
|
||||||
github.com/go-openapi/validate v0.24.0
|
github.com/go-openapi/validate v0.24.0
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||||
github.com/jessevdk/go-flags v1.6.1
|
github.com/panjf2000/ants/v2 v2.11.3
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
github.com/swaggo/files v1.0.1
|
github.com/swaggo/files v1.0.1
|
||||||
github.com/swaggo/gin-swagger v1.6.1
|
github.com/swaggo/gin-swagger v1.6.1
|
||||||
github.com/swaggo/swag v1.16.6
|
github.com/swaggo/swag v1.16.6
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
golang.org/x/crypto v0.36.0
|
golang.org/x/crypto v0.36.0
|
||||||
golang.org/x/net v0.38.0
|
google.golang.org/protobuf v1.34.1
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
gorm.io/datatypes v1.2.6
|
gorm.io/datatypes v1.2.6
|
||||||
@@ -37,12 +35,15 @@ require (
|
|||||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
|
github.com/go-logr/logr v1.4.1 // indirect
|
||||||
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-openapi/analysis v0.23.0 // indirect
|
github.com/go-openapi/analysis v0.23.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||||
|
github.com/go-openapi/loads v0.22.0 // indirect
|
||||||
|
github.com/go-openapi/spec v0.21.0 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||||
@@ -66,6 +67,7 @@ require (
|
|||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/oklog/ulid v1.3.1 // indirect
|
github.com/oklog/ulid v1.3.1 // indirect
|
||||||
|
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||||
@@ -73,14 +75,17 @@ require (
|
|||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
go.mongodb.org/mongo-driver v1.14.0 // indirect
|
go.mongodb.org/mongo-driver v1.14.0 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.24.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
||||||
go.uber.org/multierr v1.10.0 // indirect
|
go.uber.org/multierr v1.10.0 // indirect
|
||||||
golang.org/x/arch v0.8.0 // indirect
|
golang.org/x/arch v0.8.0 // indirect
|
||||||
golang.org/x/mod v0.21.0 // indirect
|
golang.org/x/mod v0.21.0 // indirect
|
||||||
|
golang.org/x/net v0.38.0 // indirect
|
||||||
golang.org/x/sync v0.12.0 // indirect
|
golang.org/x/sync v0.12.0 // indirect
|
||||||
golang.org/x/sys v0.31.0 // indirect
|
golang.org/x/sys v0.31.0 // indirect
|
||||||
golang.org/x/text v0.23.0 // indirect
|
golang.org/x/text v0.23.0 // indirect
|
||||||
golang.org/x/tools v0.26.0 // indirect
|
golang.org/x/tools v0.26.0 // indirect
|
||||||
google.golang.org/protobuf v1.34.1 // indirect
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
gorm.io/driver/mysql v1.5.6 // indirect
|
gorm.io/driver/mysql v1.5.6 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
21
go.sum
21
go.sum
@@ -15,8 +15,6 @@ github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQ
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
|
||||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
|
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
|
||||||
@@ -25,6 +23,11 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
|
|||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
|
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
|
||||||
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||||
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
|
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
|
||||||
|
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
|
github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
|
||||||
github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo=
|
github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo=
|
||||||
github.com/go-openapi/errors v0.22.2 h1:rdxhzcBUazEcGccKqbY1Y7NS8FDcMyIRr0934jrYnZg=
|
github.com/go-openapi/errors v0.22.2 h1:rdxhzcBUazEcGccKqbY1Y7NS8FDcMyIRr0934jrYnZg=
|
||||||
@@ -77,8 +80,6 @@ github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
|
|||||||
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
|
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
|
||||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
|
|
||||||
github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc=
|
|
||||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
@@ -114,6 +115,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
|||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
|
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||||
|
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||||
|
github.com/panjf2000/ants/v2 v2.11.3 h1:AfI0ngBoXJmYOpDh9m516vjqoUu2sLrIVgppI9TZVpg=
|
||||||
|
github.com/panjf2000/ants/v2 v2.11.3/go.mod h1:8u92CYMUc6gyvTIw8Ru7Mt7+/ESnJahz5EVtqfrilek=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
@@ -147,6 +152,14 @@ github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ
|
|||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
|
go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
|
||||||
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
|
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
|
||||||
|
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
|
||||||
|
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
|
||||||
|
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
|
||||||
|
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
|
||||||
|
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
|
||||||
|
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/repository"
|
||||||
|
"github.com/panjf2000/ants/v2"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,36 +31,6 @@ func NewProgressTracker() *ProgressTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartTracking 开始跟踪一个新的计划执行
|
|
||||||
func (t *ProgressTracker) StartTracking(planLogID uint, total int) {
|
|
||||||
t.mu.Lock()
|
|
||||||
defer t.mu.Unlock()
|
|
||||||
t.totalTasks[planLogID] = total
|
|
||||||
t.completedTasks[planLogID] = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment 将指定计划的完成计数加一
|
|
||||||
func (t *ProgressTracker) Increment(planLogID uint) {
|
|
||||||
t.mu.Lock()
|
|
||||||
defer t.mu.Unlock()
|
|
||||||
t.completedTasks[planLogID]++
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsComplete 检查指定计划是否已完成所有任务
|
|
||||||
func (t *ProgressTracker) IsComplete(planLogID uint) bool {
|
|
||||||
t.mu.Lock()
|
|
||||||
defer t.mu.Unlock()
|
|
||||||
return t.completedTasks[planLogID] >= t.totalTasks[planLogID]
|
|
||||||
}
|
|
||||||
|
|
||||||
// StopTracking 停止跟踪一个计划,清理内存
|
|
||||||
func (t *ProgressTracker) StopTracking(planLogID uint) {
|
|
||||||
t.mu.Lock()
|
|
||||||
defer t.mu.Unlock()
|
|
||||||
delete(t.totalTasks, planLogID)
|
|
||||||
delete(t.completedTasks, planLogID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scheduler 是核心的、持久化的任务调度器
|
// Scheduler 是核心的、持久化的任务调度器
|
||||||
type Scheduler struct {
|
type Scheduler struct {
|
||||||
logger Logger
|
logger Logger
|
||||||
@@ -68,7 +39,7 @@ type Scheduler struct {
|
|||||||
pendingTaskRepo repository.PendingTaskRepository
|
pendingTaskRepo repository.PendingTaskRepository
|
||||||
progressTracker *ProgressTracker
|
progressTracker *ProgressTracker
|
||||||
|
|
||||||
taskChannel chan *models.TaskExecutionLog // 用于向 workers 派发任务的缓冲 channel
|
pool *ants.Pool // 使用 ants 协程池来管理并发
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
@@ -83,21 +54,23 @@ func NewScheduler(pendingTaskRepo repository.PendingTaskRepository, logger Logge
|
|||||||
pollingInterval: interval,
|
pollingInterval: interval,
|
||||||
workers: numWorkers,
|
workers: numWorkers,
|
||||||
progressTracker: NewProgressTracker(),
|
progressTracker: NewProgressTracker(),
|
||||||
taskChannel: make(chan *models.TaskExecutionLog, numWorkers), // 缓冲大小与 worker 数量一致
|
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start 启动调度器,包括主轮询循环和所有工作协程
|
// Start 启动调度器,包括初始化协程池和启动主轮询循环
|
||||||
func (s *Scheduler) Start() {
|
func (s *Scheduler) Start() {
|
||||||
s.logger.Printf("任务调度器正在启动,工作协程数: %d...", s.workers)
|
s.logger.Printf("任务调度器正在启动,工作协程数: %d...", s.workers)
|
||||||
|
|
||||||
// 启动工作协程池
|
// 初始化 ants 协程池
|
||||||
s.wg.Add(s.workers)
|
pool, err := ants.NewPool(s.workers, ants.WithPanicHandler(func(err interface{}) {
|
||||||
for i := 0; i < s.workers; i++ {
|
s.logger.Printf("[严重] 任务执行时发生 panic: %v", err)
|
||||||
go s.worker(i)
|
}))
|
||||||
|
if err != nil {
|
||||||
|
panic("初始化协程池失败: " + err.Error())
|
||||||
}
|
}
|
||||||
|
s.pool = pool
|
||||||
|
|
||||||
// 启动主轮询循环
|
// 启动主轮询循环
|
||||||
s.wg.Add(1)
|
s.wg.Add(1)
|
||||||
@@ -106,15 +79,16 @@ func (s *Scheduler) Start() {
|
|||||||
s.logger.Printf("任务调度器已成功启动")
|
s.logger.Printf("任务调度器已成功启动")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop 优雅地停止调度器和所有工作协程
|
// Stop 优雅地停止调度器
|
||||||
func (s *Scheduler) Stop() {
|
func (s *Scheduler) Stop() {
|
||||||
s.logger.Printf("正在停止任务调度器...")
|
s.logger.Printf("正在停止任务调度器...")
|
||||||
s.cancel() // 发出取消信号
|
s.cancel() // 1. 发出取消信号,停止主循环
|
||||||
s.wg.Wait() // 等待所有协程完成
|
s.wg.Wait() // 2. 等待主循环完成
|
||||||
|
s.pool.Release() // 3. 释放 ants 池 (等待所有已提交的任务执行完毕)
|
||||||
s.logger.Printf("任务调度器已安全停止")
|
s.logger.Printf("任务调度器已安全停止")
|
||||||
}
|
}
|
||||||
|
|
||||||
// run 是主轮询循环,负责从数据库认领任务并派发
|
// run 是主轮询循环,负责从数据库认领任务并提交到协程池
|
||||||
func (s *Scheduler) run() {
|
func (s *Scheduler) run() {
|
||||||
defer s.wg.Done()
|
defer s.wg.Done()
|
||||||
ticker := time.NewTicker(s.pollingInterval)
|
ticker := time.NewTicker(s.pollingInterval)
|
||||||
@@ -123,16 +97,22 @@ func (s *Scheduler) run() {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-s.ctx.Done():
|
case <-s.ctx.Done():
|
||||||
close(s.taskChannel) // 关闭 channel,让 workers 退出循环
|
|
||||||
return
|
return
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
s.claimAndDispatch()
|
s.claimAndSubmit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// claimAndDispatch 认领一个任务并将其发送到派发通道
|
// claimAndSubmit 认领一个任务并将其提交到 ants 协程池
|
||||||
func (s *Scheduler) claimAndDispatch() {
|
func (s *Scheduler) claimAndSubmit() {
|
||||||
|
// ants 池的 Running() 数量可以用来提前判断是否繁忙,但这只是一个快照,
|
||||||
|
// 真正的阻塞和背压由 Submit() 方法保证。
|
||||||
|
if s.pool.Running() >= s.workers {
|
||||||
|
// 可选:如果所有 worker 都在忙,可以跳过本次数据库查询,以减轻数据库压力
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
claimedLog, err := s.pendingTaskRepo.ClaimNextDueTask()
|
claimedLog, err := s.pendingTaskRepo.ClaimNextDueTask()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
@@ -141,39 +121,29 @@ func (s *Scheduler) claimAndDispatch() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将认领到的任务发送到派发通道
|
// 将任务处理逻辑作为一个函数提交给 ants 池。
|
||||||
// 如果所有 worker 都在忙,这里会阻塞,从而实现背压,防止队列无限增长
|
// 如果池已满,Submit 方法会阻塞,直到有协程空闲出来,这自然地实现了背压。
|
||||||
select {
|
err = s.pool.Submit(func() {
|
||||||
case s.taskChannel <- claimedLog:
|
s.processTask(claimedLog)
|
||||||
s.logger.Printf("成功认领并派发任务, 日志ID: %d, 任务ID: %d", claimedLog.ID, claimedLog.TaskID)
|
})
|
||||||
case <-s.ctx.Done():
|
if err != nil {
|
||||||
// 如果在等待派发时调度器被停止,需要处理这个未派发的任务
|
// 如果在调度器停止期间提交任务,可能会发生此错误
|
||||||
// 简单的处理方式是忽略它,让清理器进程后续来处理这个 'running' 状态的任务
|
s.logger.Printf("向协程池提交任务失败: %v", err)
|
||||||
s.logger.Printf("在派发任务时调度器被停止, 日志ID: %d", claimedLog.ID)
|
// 可以在这里添加逻辑,将任务状态恢复为 pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// worker 是工作协程的实现
|
|
||||||
func (s *Scheduler) worker(id int) {
|
|
||||||
defer s.wg.Done()
|
|
||||||
s.logger.Printf("工作协程 #%d 已启动", id)
|
|
||||||
for claimedLog := range s.taskChannel {
|
|
||||||
s.processTask(id, claimedLog)
|
|
||||||
}
|
|
||||||
s.logger.Printf("工作协程 #%d 已停止", id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// processTask 包含了处理单个任务的完整逻辑
|
// processTask 包含了处理单个任务的完整逻辑
|
||||||
func (s *Scheduler) processTask(workerID int, claimedLog *models.TaskExecutionLog) {
|
func (s *Scheduler) processTask(claimedLog *models.TaskExecutionLog) {
|
||||||
s.logger.Printf("工作协程 #%d 正在处理任务, 日志ID: %d, 任务ID: %d, 任务名称: %s",
|
s.logger.Printf("开始处理任务, 日志ID: %d, 任务ID: %d, 任务名称: %s",
|
||||||
workerID, claimedLog.ID, claimedLog.TaskID, claimedLog.Task.Name)
|
claimedLog.ID, claimedLog.TaskID, claimedLog.Task.Name)
|
||||||
|
|
||||||
// 在这里,我们将根据 claimedLog.TaskID 或未来的 Task.Kind 来分发给不同的处理器
|
// 在这里,我们将根据 claimedLog.TaskID 或未来的 Task.Kind 来分发给不同的处理器
|
||||||
// 现在,我们只做一个模拟执行
|
// 现在,我们只做一个模拟执行
|
||||||
time.Sleep(2 * time.Second) // 模拟任务执行耗时
|
time.Sleep(2 * time.Second) // 模拟任务执行耗时
|
||||||
|
|
||||||
// 任务执行完毕后,更新日志和进度
|
// 任务执行完毕后,更新日志和进度
|
||||||
s.logger.Printf("工作协程 #%d 已完成任务, 日志ID: %d", workerID, claimedLog.ID)
|
s.logger.Printf("完成任务, 日志ID: %d", claimedLog.ID)
|
||||||
|
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
// 未来的逻辑将在这里展开:
|
// 未来的逻辑将在这里展开:
|
||||||
@@ -186,3 +156,30 @@ func (s *Scheduler) processTask(workerID int, claimedLog *models.TaskExecutionLo
|
|||||||
//
|
//
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProgressTracker 的方法实现
|
||||||
|
func (t *ProgressTracker) StartTracking(planLogID uint, total int) {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
|
t.totalTasks[planLogID] = total
|
||||||
|
t.completedTasks[planLogID] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ProgressTracker) Increment(planLogID uint) {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
|
t.completedTasks[planLogID]++
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ProgressTracker) IsComplete(planLogID uint) bool {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
|
return t.completedTasks[planLogID] >= t.totalTasks[planLogID]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *ProgressTracker) StopTracking(planLogID uint) {
|
||||||
|
t.mu.Lock()
|
||||||
|
defer t.mu.Unlock()
|
||||||
|
delete(t.totalTasks, planLogID)
|
||||||
|
delete(t.completedTasks, planLogID)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user