feat: 为执行后端增加独立容量池
test / python (pull_request) Successful in 13s
test / shell (pull_request) Successful in 20s
test / go (pull_request) Successful in 5m54s

This commit is contained in:
2026-09-21 07:21:38 +00:00
parent d06845bc3c
commit fadc93a0bf
9 changed files with 245 additions and 21 deletions
+30 -5
View File
@@ -4,8 +4,11 @@ import (
"context"
"errors"
"fmt"
"sync/atomic"
"time"
"golang.org/x/sync/errgroup"
runnerv1 "gitea.dev/actionslib/runner/v1"
)
@@ -19,10 +22,12 @@ type PollerConfig struct {
Labels []string
EmptyBackoff time.Duration
ErrorBackoff time.Duration
Capacity int
}
// Poller is the scheduler component. Once Gitea assigns a task, it never
// fetches another one until the current assignment is durably dispatched.
// Poller is the scheduler component. Each fetcher keeps its assigned task
// until that assignment is durably dispatched; all fetchers share one runner
// declaration and a monotonic tasks version.
type Poller struct {
Client PollClient
Scheduler *Scheduler
@@ -49,9 +54,21 @@ func (p Poller) Run(ctx context.Context) error {
if errorBackoff <= 0 {
errorBackoff = 5 * time.Second
}
var tasksVersion int64
capacity := p.Config.Capacity
if capacity < 1 {
capacity = 1
}
var tasksVersion atomic.Int64
group, groupContext := errgroup.WithContext(ctx)
for range capacity {
group.Go(func() error { return p.runFetcher(groupContext, &tasksVersion, emptyBackoff, errorBackoff) })
}
return group.Wait()
}
func (p Poller) runFetcher(ctx context.Context, tasksVersion *atomic.Int64, emptyBackoff, errorBackoff time.Duration) error {
for {
response, err := p.Client.FetchTask(ctx, tasksVersion)
response, err := p.Client.FetchTask(ctx, tasksVersion.Load())
if err != nil {
if ctx.Err() != nil {
return nil
@@ -69,7 +86,7 @@ func (p Poller) Run(ctx context.Context) error {
}
continue
}
tasksVersion = response.GetTasksVersion()
storeMaximum(tasksVersion, response.GetTasksVersion())
task := response.GetTask()
if task == nil {
if !wait(ctx, emptyBackoff) {
@@ -93,6 +110,14 @@ func (p Poller) Run(ctx context.Context) error {
}
}
func storeMaximum(value *atomic.Int64, candidate int64) {
for current := value.Load(); candidate > current; current = value.Load() {
if value.CompareAndSwap(current, candidate) {
return
}
}
}
func (p Poller) report(err error) {
if p.OnError != nil {
p.OnError(err)