Merge pull request #129 from vito/nix-docker-queue-singletons

Remove docker client + queue singletons
This commit is contained in:
Brad Rydzewski 2014-02-25 22:55:38 -08:00
commit 9aa5f95e92
7 changed files with 38 additions and 36 deletions

View file

@ -123,6 +123,8 @@ func vet(path string) {
} }
func run(path string) { func run(path string) {
dockerClient := docker.New()
// parse the Drone yml file // parse the Drone yml file
s, err := script.ParseBuildFile(path) s, err := script.ParseBuildFile(path)
if err != nil { if err != nil {
@ -175,7 +177,7 @@ func run(path string) {
// loop through and create builders // loop through and create builders
for _, b := range builds { //script.Builds { for _, b := range builds { //script.Builds {
builder := build.New(docker.DefaultClient) builder := build.New(dockerClient)
builder.Build = b builder.Build = b
builder.Repo = &code builder.Repo = &code
builder.Key = key builder.Key = key

View file

@ -5,7 +5,9 @@ import (
"flag" "flag"
"log" "log"
"net/http" "net/http"
"runtime"
"strings" "strings"
"time"
"code.google.com/p/go.net/websocket" "code.google.com/p/go.net/websocket"
"github.com/GeertJohan/go.rice" "github.com/GeertJohan/go.rice"
@ -13,10 +15,12 @@ import (
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
"github.com/russross/meddler" "github.com/russross/meddler"
"github.com/drone/drone/pkg/build/docker"
"github.com/drone/drone/pkg/channel" "github.com/drone/drone/pkg/channel"
"github.com/drone/drone/pkg/database" "github.com/drone/drone/pkg/database"
"github.com/drone/drone/pkg/database/migrate" "github.com/drone/drone/pkg/database/migrate"
"github.com/drone/drone/pkg/handler" "github.com/drone/drone/pkg/handler"
"github.com/drone/drone/pkg/queue"
) )
var ( var (
@ -118,6 +122,11 @@ func setupStatic() {
// setup routes for serving dynamic content. // setup routes for serving dynamic content.
func setupHandlers() { func setupHandlers() {
queueRunner := queue.NewRunner(docker.New(), 300*time.Second)
queue := queue.Start(runtime.NumCPU(), queueRunner)
hookHandler := handler.NewHookHandler(queue)
m := pat.New() m := pat.New()
m.Get("/login", handler.ErrorHandler(handler.Login)) m.Get("/login", handler.ErrorHandler(handler.Login))
m.Post("/login", handler.ErrorHandler(handler.Authorize)) m.Post("/login", handler.ErrorHandler(handler.Authorize))
@ -177,7 +186,7 @@ func setupHandlers() {
m.Get("/account/admin/users", handler.AdminHandler(handler.AdminUserList)) m.Get("/account/admin/users", handler.AdminHandler(handler.AdminUserList))
// handlers for GitHub post-commit hooks // handlers for GitHub post-commit hooks
m.Post("/hook/github.com", handler.ErrorHandler(handler.Hook)) m.Post("/hook/github.com", handler.ErrorHandler(hookHandler.Hook))
// handlers for first-time installation // handlers for first-time installation
m.Get("/install", handler.ErrorHandler(handler.Install)) m.Get("/install", handler.ErrorHandler(handler.Install))

View file

@ -29,8 +29,6 @@ const (
// Enables verbose logging to the Terminal window // Enables verbose logging to the Terminal window
var Logging = true var Logging = true
var DefaultClient = New() // TEMPORARY; PLEASE CONSTRUCT/INJECT YOURSELF
// New creates an instance of the Docker Client // New creates an instance of the Docker Client
func New() *Client { func New() *Client {
c := &Client{} c := &Client{}

View file

@ -13,10 +13,19 @@ import (
"github.com/drone/go-github/github" "github.com/drone/go-github/github"
) )
type HookHandler struct {
queue *queue.Queue
}
func NewHookHandler(queue *queue.Queue) *HookHandler {
return &HookHandler{
queue: queue,
}
}
// Processes a generic POST-RECEIVE hook and // Processes a generic POST-RECEIVE hook and
// attempts to trigger a build. // attempts to trigger a build.
func Hook(w http.ResponseWriter, r *http.Request) error { func (h *HookHandler) Hook(w http.ResponseWriter, r *http.Request) error {
// handle github ping // handle github ping
if r.Header.Get("X-Github-Event") == "ping" { if r.Header.Get("X-Github-Event") == "ping" {
return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK)
@ -25,7 +34,7 @@ func Hook(w http.ResponseWriter, r *http.Request) error {
// if this is a pull request route // if this is a pull request route
// to a different handler // to a different handler
if r.Header.Get("X-Github-Event") == "pull_request" { if r.Header.Get("X-Github-Event") == "pull_request" {
PullRequestHook(w, r) h.PullRequestHook(w, r)
return nil return nil
} }
@ -160,14 +169,13 @@ func Hook(w http.ResponseWriter, r *http.Request) error {
//realtime.CommitPending(repo.UserID, repo.TeamID, repo.ID, commit.ID, repo.Private) //realtime.CommitPending(repo.UserID, repo.TeamID, repo.ID, commit.ID, repo.Private)
//realtime.BuildPending(repo.UserID, repo.TeamID, repo.ID, commit.ID, build.ID, repo.Private) //realtime.BuildPending(repo.UserID, repo.TeamID, repo.ID, commit.ID, build.ID, repo.Private)
queue.Add(&queue.BuildTask{Repo: repo, Commit: commit, Build: build, Script: buildscript}) //Push(repo, commit, build, buildscript) h.queue.Add(&queue.BuildTask{Repo: repo, Commit: commit, Build: build, Script: buildscript}) //Push(repo, commit, build, buildscript)
// OK! // OK!
return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) return RenderText(w, http.StatusText(http.StatusOK), http.StatusOK)
} }
func PullRequestHook(w http.ResponseWriter, r *http.Request) { func (h *HookHandler) PullRequestHook(w http.ResponseWriter, r *http.Request) {
// get the payload of the message // get the payload of the message
// this should contain a json representation of the // this should contain a json representation of the
// repository and commit details // repository and commit details
@ -276,7 +284,7 @@ func PullRequestHook(w http.ResponseWriter, r *http.Request) {
// notify websocket that a new build is pending // notify websocket that a new build is pending
// TODO we should, for consistency, just put this inside Queue.Add() // TODO we should, for consistency, just put this inside Queue.Add()
queue.Add(&queue.BuildTask{Repo: repo, Commit: commit, Build: build, Script: buildscript}) h.queue.Add(&queue.BuildTask{Repo: repo, Commit: commit, Build: build, Script: buildscript})
// OK! // OK!
RenderText(w, http.StatusText(http.StatusOK), http.StatusOK) RenderText(w, http.StatusText(http.StatusOK), http.StatusOK)

View file

@ -10,29 +10,29 @@ import (
"github.com/drone/drone/pkg/build/script" "github.com/drone/drone/pkg/build/script"
) )
type Runner interface { type BuildRunner interface {
Run(buildScript *script.Build, repo *repo.Repo, key []byte, buildOutput io.Writer) (success bool, err error) Run(buildScript *script.Build, repo *repo.Repo, key []byte, buildOutput io.Writer) (success bool, err error)
} }
type runner struct { type buildRunner struct {
dockerClient *docker.Client dockerClient *docker.Client
timeout time.Duration timeout time.Duration
} }
func newRunner(dockerClient *docker.Client, timeout time.Duration) *runner { func NewBuildRunner(dockerClient *docker.Client, timeout time.Duration) BuildRunner {
return &runner{ return &buildRunner{
dockerClient: dockerClient, dockerClient: dockerClient,
timeout: timeout, timeout: timeout,
} }
} }
func (r *runner) Run(buildScript *script.Build, repo *repo.Repo, key []byte, buildOutput io.Writer) (bool, error) { func (runner *buildRunner) Run(buildScript *script.Build, repo *repo.Repo, key []byte, buildOutput io.Writer) (bool, error) {
builder := build.New(r.dockerClient) builder := build.New(runner.dockerClient)
builder.Build = buildScript builder.Build = buildScript
builder.Repo = repo builder.Repo = repo
builder.Key = key builder.Key = key
builder.Stdout = buildOutput builder.Stdout = buildOutput
builder.Timeout = r.timeout builder.Timeout = runner.timeout
err := builder.Run() err := builder.Run()

View file

@ -1,11 +1,8 @@
package queue package queue
import ( import (
"github.com/drone/drone/pkg/build/docker"
"github.com/drone/drone/pkg/build/script" "github.com/drone/drone/pkg/build/script"
. "github.com/drone/drone/pkg/model" . "github.com/drone/drone/pkg/model"
"runtime"
"time"
) )
// A Queue dispatches tasks to workers. // A Queue dispatches tasks to workers.
@ -25,24 +22,12 @@ type BuildTask struct {
Script *script.Build Script *script.Build
} }
var defaultQueue = Start(runtime.NumCPU(), newRunner(docker.DefaultClient, 300*time.Second)) // TEMPORARY; INJECT PLEASE // Start N workers with the given build runner.
func Start(workers int, runner BuildRunner) *Queue {
var Add = defaultQueue.Add // TEMPORARY; INJECT PLEASE
func Start(workers int, runner Runner) *Queue {
// get the number of CPUs. Since builds
// tend to be CPU-intensive we should only
// execute 1 build per CPU.
// must be at least 1
// if ncpu < 1 {
// ncpu = 1
// }
tasks := make(chan *BuildTask) tasks := make(chan *BuildTask)
queue := &Queue{tasks: tasks} queue := &Queue{tasks: tasks}
// spawn a worker for each CPU
for i := 0; i < workers; i++ { for i := 0; i < workers; i++ {
worker := worker{ worker := worker{
runner: runner, runner: runner,

View file

@ -17,7 +17,7 @@ import (
) )
type worker struct { type worker struct {
runner Runner runner BuildRunner
} }
// work is a function that will infinitely // work is a function that will infinitely