//specificImportResult shows a result item for an import path and given revision func specificImportResult(w http.ResponseWriter, req *http.Request, ctx httputil.Context) (e *httputil.Error) { w.Header().Set("Content-Type", "text/html") if err := req.ParseForm(); err != nil { e = httputil.Errorf(err, "error parsing form") return } imp, rev := grab(req.Form, "import"), grab(req.Form, "rev") if err := T("result/specific_import_result.html").Execute(w, []string{imp, rev}); err != nil { e = httputil.Errorf(err, "error executing index template") } return }
//work shows recent work items func work(w http.ResponseWriter, req *http.Request, ctx httputil.Context) (e *httputil.Error) { m := newManager(ctx) res, err := m.Work(0, 20) if err != nil { e = httputil.Errorf(err, "couldn't query for work results") return } w.Header().Set("Content-Type", "text/html") if err := T("work/work.html").Execute(w, res); err != nil { e = httputil.Errorf(err, "error executing index template") } return }
//pkg displays a list of import paths tested by goci func pkg(w http.ResponseWriter, req *http.Request, ctx httputil.Context) (e *httputil.Error) { m := newManager(ctx) res, err := m.Packages() if err != nil { e = httputil.Errorf(err, "error grabbing package list") return } w.Header().Set("Content-Type", "text/html") if err := T("pkg/pkg.html").Execute(w, res); err != nil { e = httputil.Errorf(err, "error executing index template") } return }
//result shows recent result items func result(w http.ResponseWriter, req *http.Request, ctx httputil.Context) (e *httputil.Error) { w.Header().Set("Content-Type", "text/html") if err := T("result/result.html").Execute(w, nil); err != nil { e = httputil.Errorf(err, "error executing index template") } return }
func ping(w http.ResponseWriter, req *http.Request, ctx httputil.Context) (e *httputil.Error) { if err := tracker.DefaultTracker.Ping(req, nil, nil); err != nil { e = httputil.Errorf(err, "error sending ping") return } fmt.Fprintf(w, "ping!") return }
//specificWork shows a work item with the given key func specificWork(w http.ResponseWriter, req *http.Request, ctx httputil.Context) (e *httputil.Error) { w.Header().Set("Content-Type", "text/html") if err := req.ParseForm(); err != nil { e = httputil.Errorf(err, "error parsing form") return } m := newManager(ctx) work, err := m.SpecificWork(grab(req.Form, "key")) if err != nil { e = httputil.Errorf(err, "error grabbing work item") return } if err := T("work/specific_work.html").Execute(w, work); err != nil { e = httputil.Errorf(err, "error executing index template") } return }
//index shows the main homepage of goci func index(w http.ResponseWriter, req *http.Request, ctx httputil.Context) (e *httputil.Error) { if req.URL.Path != "/" { notFound(w, req) return } m := newManager(ctx) res, err := m.Index() if err != nil { e = httputil.Errorf(err, "couldn't query for test results") return } w.Header().Set("Content-Type", "text/html") if err := T("index/index.html").Execute(w, res); err != nil { e = httputil.Errorf(err, "error executing index template") } return }
func lease(w http.ResponseWriter, req *http.Request, ctx httputil.Context) (e *httputil.Error) { b, r, err := tracker.LeasePair(ctx) if err != nil { e = httputil.Errorf(err, "error leasing pair") return } fmt.Fprintf(w, "%+v\n%+v\n", b, r) return }
//image returns an image representing the most recent build status for an import path func image(w http.ResponseWriter, req *http.Request, ctx httputil.Context) (e *httputil.Error) { w.Header().Set("Content-Type", "text/html") if err := req.ParseForm(); err != nil { e = httputil.Errorf(err, "error parsing request form") return } imp := grab(req.Form, "import") _ = imp return }
//dispatchWork is the handler that gets called for a queue item. It grabs a builder //and runner and dispatches the work item to them, recoding when that operation //started. func dispatchWork(w http.ResponseWriter, req *http.Request, ctx httputil.Context) (e *httputil.Error) { //find all the documents that are waiting or (processing and their attempt is //taking too long) type L []interface{} selector := bson.M{ "$or": L{ bson.M{"status": entities.WorkStatusWaiting}, bson.M{ "status": entities.WorkStatusProcessing, "attemptlog.0.when": bson.M{"$lt": time.Now().Add(-1 * attemptTime)}, }, }, } iter := ctx.DB.C("Work").Find(selector).Iter() var work entities.Work for iter.Next(&work) { //if its a processing task with too many attempts, store it as a dispatch //error. if len(work.AttemptLog) >= maxAttempts { ctx.Infof("Work item %s had too many attempts", work.ID) args := &rpc.DispatchResponse{ Key: work.ID.Hex(), Error: "Unable to complete Work item. Too many failed attempts.", WorkRev: work.Revision, } //send it off to the response rpc respUrl := httputil.Absolute(router.Lookup("Response")) cl := client.New(respUrl, http.DefaultClient, client.JsonCodec) if err := cl.Call("Response.DispatchError", args, new(rpc.None)); err != nil { ctx.Infof("Couldn't store a dispatch error for work item %s: %s", work.ID, err) } continue } //attempt to dispatch the work item err := dispatchWorkItem(ctx, work) if err != nil { ctx.Errorf("Error dispatching work: %s", err) } } //check for errors running the iteration if err := iter.Err(); err != nil { ctx.Errorf("Error iterating over work items: %s", err) e = httputil.Errorf(err, "Error iterating over work items") return } return }
func addwork(w http.ResponseWriter, req *http.Request, ctx httputil.Context) (e *httputil.Error) { //create our little work item // q := rpc.Work{ // Revision: "8488aea525fb04d90328917112b30e5ec01f4895", // ImportPath: "github.com/zeebo/goci", // Subpackages: true, // } q := rpc.Work{ Revision: "e9dd26552f10d390b5f9f59c6a9cfdc30ed1431c", ImportPath: "github.com/zeebo/irc", } //add it to the queue if err := workqueue.QueueWork(ctx, q); err != nil { e = httputil.Errorf(err, "error adding work item to queue") return } return }
func dispatchNotifications(w http.ResponseWriter, req *http.Request, ctx httputil.Context) (e *httputil.Error) { //find all documents that are waiting or (processing and their attempt is //taking too long) type L []interface{} selector := bson.M{ "$or": L{ bson.M{"status": entities.NotifStatusWaiting}, bson.M{ "status": entities.NotifStatusProcessing, "attemptlog.0.when": bson.M{"$lt": time.Now().Add(-1 * attemptTime)}, }, }, } iter := ctx.DB.C("Notification").Find(selector).Iter() var n entities.Notification for iter.Next(&n) { //if it's processing with too may attempts then just give up if len(n.AttemptLog) >= maxAttempts { ctx.Infof("Notification %s had too many attempts", n.ID) ops := []txn.Op{{ C: "Notification", Id: n.ID, Assert: bson.M{ "status": entities.NotifStatusProcessing, "revision": n.Revision, }, Update: bson.M{ "$set": bson.M{"status": entities.NotifStatusError}, "$inc": bson.M{"revision": 1}, }, }} //try to update the notification err := ctx.R.Run(ops, bson.NewObjectId(), nil) if err == txn.ErrAborted { ctx.Infof("Lost race updating notification %s", n.ID) err = nil } if err != nil { ctx.Errorf("Error updating notification %s: %s", n.ID, err) } continue } err := dispatchNotificationItem(ctx, &n) if err != nil { ctx.Errorf("Error processing notification %s: %s", n.ID, err) continue } //update the thing as being done ops := []txn.Op{{ C: "Notification", Id: n.ID, Assert: bson.M{ "revision": n.Revision, }, Update: bson.M{ "$inc": bson.M{"revision": 1}, "$set": bson.M{"status": entities.NotifStatusCompleted}, }, }} err = ctx.R.Run(ops, bson.NewObjectId(), nil) if err == txn.ErrAborted { ctx.Infof("Lost the race setting the notification %s to complete", n.ID) err = nil } if err != nil { ctx.Errorf("Error setting notification %s to complete: %s", n.ID, err) } } //check for errors in the iteration if err := iter.Err(); err != nil { ctx.Errorf("Error iterating over notifications: %s", err) e = httputil.Errorf(err, "Error iterating over notifications") return } return }