|
|
|
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
|
|
|
// Use of this source code is governed by the Polyform License
|
|
|
|
// that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package poller
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"git.awesome-for.me/liuzhiguo/drone-go/drone"
|
|
|
|
"git.awesome-for.me/liuzhiguo/runner-go/client"
|
|
|
|
"git.awesome-for.me/liuzhiguo/runner-go/logger"
|
|
|
|
)
|
|
|
|
|
|
|
|
var noContext = context.Background()
|
|
|
|
|
|
|
|
// Poller polls the server for pending stages and dispatches
|
|
|
|
// for execution by the Runner.
|
|
|
|
type Poller struct {
|
|
|
|
Client client.Client
|
|
|
|
Filter *client.Filter
|
|
|
|
|
|
|
|
// Dispatch is dispatches the resource for processing.
|
|
|
|
// It is invoked by the poller when a resource is
|
|
|
|
// received by the remote system.
|
|
|
|
Dispatch func(context.Context, *drone.Stage) error
|
|
|
|
}
|
|
|
|
|
|
|
|
// Poll opens N connections to the server to poll for pending
|
|
|
|
// stages for execution. Pending stages are dispatched to a
|
|
|
|
// Runner for execution.
|
|
|
|
func (p *Poller) Poll(ctx context.Context, n int) {
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
wg.Add(1)
|
|
|
|
go func(i int) {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
wg.Done()
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
p.poll(ctx, i+1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
wg.Wait()
|
|
|
|
}
|
|
|
|
|
|
|
|
// poll requests a stage for execution from the server, and then
|
|
|
|
// dispatches for execution.
|
|
|
|
func (p *Poller) poll(ctx context.Context, thread int) error {
|
|
|
|
log := logger.FromContext(ctx).WithField("thread", thread)
|
|
|
|
log.WithField("thread", thread).Debug("poller: request stage from remote server")
|
|
|
|
|
|
|
|
// request a new build stage for execution from the central
|
|
|
|
// build server.
|
|
|
|
stage, err := p.Client.Request(ctx, p.Filter)
|
|
|
|
if err == context.Canceled || err == context.DeadlineExceeded {
|
|
|
|
log.WithError(err).Trace("poller: no stage returned")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
log.WithError(err).Error("poller: cannot request stage")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// exit if a nil or empty stage is returned from the system
|
|
|
|
// and allow the runner to retry.
|
|
|
|
if stage == nil || stage.ID == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return p.Dispatch(
|
|
|
|
logger.WithContext(noContext, log), stage)
|
|
|
|
}
|