Skip to content

Commit

Permalink
create router constructor that accepts client
Browse files Browse the repository at this point in the history
  • Loading branch information
vin-rmdn committed Sep 26, 2024
1 parent 6536d93 commit c720c7b
Show file tree
Hide file tree
Showing 6 changed files with 234 additions and 249 deletions.
141 changes: 141 additions & 0 deletions webui/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package webui

import (
"strconv"
"time"

"github.com/gocraft/web"
"github.com/gojek/work"
)

type context struct {
client *work.Client
}

func (c *context) ping(rw web.ResponseWriter, r *web.Request) {
render(rw, map[string]string{"ping": "pong", "current_time": time.Now().Format(time.RFC3339)}, nil)
}

func (c *context) queues(rw web.ResponseWriter, r *web.Request) {
response, err := c.client.Queues()
render(rw, response, err)
}

func (c *context) workerPools(rw web.ResponseWriter, r *web.Request) {
response, err := c.client.WorkerPoolHeartbeats()
render(rw, response, err)
}

func (c *context) busyWorkers(rw web.ResponseWriter, r *web.Request) {
observations, err := c.client.WorkerObservations()
if err != nil {
renderError(rw, err)
return
}

var busyObservations []*work.WorkerObservation
for _, ob := range observations {
if ob.IsBusy {
busyObservations = append(busyObservations, ob)
}
}

render(rw, busyObservations, err)
}

func (c *context) retryJobs(rw web.ResponseWriter, r *web.Request) {
page, err := parsePage(r)
if err != nil {
renderError(rw, err)
return
}

jobs, count, err := c.client.RetryJobs(page)
if err != nil {
renderError(rw, err)
return
}

response := struct {
Count int64 `json:"count"`
Jobs []*work.RetryJob `json:"jobs"`
}{Count: count, Jobs: jobs}

render(rw, response, err)
}

func (c *context) scheduledJobs(rw web.ResponseWriter, r *web.Request) {
page, err := parsePage(r)
if err != nil {
renderError(rw, err)
return
}

jobs, count, err := c.client.ScheduledJobs(page)
if err != nil {
renderError(rw, err)
return
}

response := struct {
Count int64 `json:"count"`
Jobs []*work.ScheduledJob `json:"jobs"`
}{Count: count, Jobs: jobs}

render(rw, response, err)
}

func (c *context) deadJobs(rw web.ResponseWriter, r *web.Request) {
page, err := parsePage(r)
if err != nil {
renderError(rw, err)
return
}

jobs, count, err := c.client.DeadJobs(page)
if err != nil {
renderError(rw, err)
return
}

response := struct {
Count int64 `json:"count"`
Jobs []*work.DeadJob `json:"jobs"`
}{Count: count, Jobs: jobs}

render(rw, response, err)
}

func (c *context) deleteDeadJob(rw web.ResponseWriter, r *web.Request) {
diedAt, err := strconv.ParseInt(r.PathParams["died_at"], 10, 64)
if err != nil {
renderError(rw, err)
return
}

err = c.client.DeleteDeadJob(diedAt, r.PathParams["job_id"])

render(rw, map[string]string{"status": "ok"}, err)
}

func (c *context) retryDeadJob(rw web.ResponseWriter, r *web.Request) {
diedAt, err := strconv.ParseInt(r.PathParams["died_at"], 10, 64)
if err != nil {
renderError(rw, err)
return
}

err = c.client.RetryDeadJob(diedAt, r.PathParams["job_id"])

render(rw, map[string]string{"status": "ok"}, err)
}

func (c *context) deleteAllDeadJobs(rw web.ResponseWriter, r *web.Request) {
err := c.client.DeleteAllDeadJobs()
render(rw, map[string]string{"status": "ok"}, err)
}

func (c *context) retryAllDeadJobs(rw web.ResponseWriter, r *web.Request) {
err := c.client.RetryAllDeadJobs()
render(rw, map[string]string{"status": "ok"}, err)
}
11 changes: 0 additions & 11 deletions webui/options.go

This file was deleted.

52 changes: 27 additions & 25 deletions webui/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,39 @@ import (
"html/template"

"github.com/gocraft/web"
"github.com/gojek/work"
)

func (s *Server) setupRouter() {
s.router.Middleware(func(c *context, rw web.ResponseWriter, r *web.Request, next web.NextMiddlewareFunc) {
c.Server = s
next(rw, r)
})
s.router.Middleware(func(rw web.ResponseWriter, r *web.Request, next web.NextMiddlewareFunc) {
type RouterOptions struct {
PathPrefix string
}

func NewRouter(client *work.Client, opts RouterOptions) *web.Router {
ctx := context{client: client}
router := web.New(ctx)

router.Middleware(func(rw web.ResponseWriter, r *web.Request, next web.NextMiddlewareFunc) {
rw.Header().Set("Content-Type", "application/json; charset=utf-8")
next(rw, r)
})

subRouter := s.router.Subrouter(context{}, s.pathPrefix)

subRouter.Get("/ping", (*context).ping)
subRouter.Get("/queues", (*context).queues)
subRouter.Get("/worker_pools", (*context).workerPools)
subRouter.Get("/busy_workers", (*context).busyWorkers)
subRouter.Get("/retry_jobs", (*context).retryJobs)
subRouter.Get("/scheduled_jobs", (*context).scheduledJobs)
subRouter.Get("/dead_jobs", (*context).deadJobs)
subRouter.Post("/delete_dead_job/:died_at:\\d.*/:job_id", (*context).deleteDeadJob)
subRouter.Post("/retry_dead_job/:died_at:\\d.*/:job_id", (*context).retryDeadJob)
subRouter.Post("/delete_all_dead_jobs", (*context).deleteAllDeadJobs)
subRouter.Post("/retry_all_dead_jobs", (*context).retryAllDeadJobs)
subRouter := router.Subrouter(ctx, opts.PathPrefix)
subRouter.Get("/ping", ctx.ping)
subRouter.Get("/queues", ctx.queues)
subRouter.Get("/worker_pools", ctx.workerPools)
subRouter.Get("/busy_workers", ctx.busyWorkers)
subRouter.Get("/retry_jobs", ctx.retryJobs)
subRouter.Get("/scheduled_jobs", ctx.scheduledJobs)
subRouter.Get("/dead_jobs", ctx.deadJobs)
subRouter.Post("/delete_dead_job/:died_at:\\d.*/:job_id", ctx.deleteDeadJob)
subRouter.Post("/retry_dead_job/:died_at:\\d.*/:job_id", ctx.retryDeadJob)
subRouter.Post("/delete_all_dead_jobs", ctx.deleteAllDeadJobs)
subRouter.Post("/retry_all_dead_jobs", ctx.retryAllDeadJobs)

//
// Build the HTML page:
//
assetRouter := subRouter.Subrouter(context{}, "")
assetRouter := subRouter.Subrouter(ctx, "")
assetRouter.Get("/", func(c *context, rw web.ResponseWriter, req *web.Request) {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")

Expand All @@ -46,11 +49,8 @@ func (s *Server) setupRouter() {
return
}

data := struct {
PathPrefix string
}{
PathPrefix: c.pathPrefix,
}
// TODO: check if map works
data := struct{ PathPrefix string }{PathPrefix: opts.PathPrefix}

err = indexTemplate.Execute(rw, data)
if err != nil {
Expand All @@ -63,4 +63,6 @@ func (s *Server) setupRouter() {
rw.Header().Set("Content-Type", "application/javascript; charset=utf-8")
_, _ = rw.Write(mustAsset("work.js"))
})

return router
}
52 changes: 52 additions & 0 deletions webui/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package webui

import (
"net/http"
"sync"

"github.com/braintree/manners"
"github.com/gocraft/web"
"github.com/gojek/work"
"github.com/gomodule/redigo/redis"
)

// Server implements an HTTP server which exposes a JSON API to view and manage gojek/work items.
type Server struct {
namespace string
pool *redis.Pool
hostPort string
server *manners.GracefulServer
wg sync.WaitGroup
router *web.Router
pathPrefix string
}

// NewServer creates and returns a new server. The 'namespace' param is the redis namespace to use. The hostPort param is the address to bind on to expose the API.
func NewServer(namespace string, pool *redis.Pool, hostPort string) *Server {
client := work.NewClient(namespace, pool)
router := NewRouter(client, RouterOptions{})

return &Server{
namespace: namespace,
pool: pool,
hostPort: hostPort,
router: router,
server: manners.NewWithServer(&http.Server{Addr: hostPort, Handler: router}),
}
}

// Start starts the server listening for requests on the hostPort specified in NewServer.
func (w *Server) Start() {
w.wg.Add(1)
go func(w *Server) {
_ = w.server.ListenAndServe()

w.wg.Done()
}(w)
}

// Stop stops the server and blocks until it has finished.
func (w *Server) Stop() {
w.server.Close()
w.wg.Wait()
}
Loading

0 comments on commit c720c7b

Please sign in to comment.