Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve search functionality #35

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ aurora is a web-based Beanstalkd queue server console written in Go and works on
- You can move jobs between tubes
- Ability to Pause tubes
- Search jobs data field
- Search jobs by ID
- Customizable UI (code highlighter, choose columns, edit auto refresh seconds, pause tube seconds)

## Installation
Expand Down
2 changes: 1 addition & 1 deletion handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func handlerTube(w http.ResponseWriter, r *http.Request) {
_, _ = io.WriteString(w, `{"result":true}`)
return
case "search":
content := searchTube(server, tube, r.URL.Query().Get("limit"), r.URL.Query().Get("searchStr"))
content := searchTube(server, tube, r.URL.Query().Get("limit"), r.URL.Query().Get("id"), r.URL.Query().Get("state"), r.URL.Query().Get("searchStr"))
_, _ = io.WriteString(w, tplTube(content, server, tube))
return
case "addSample":
Expand Down
67 changes: 55 additions & 12 deletions lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,13 +263,14 @@ func clearTubes(server string, data url.Values) {

// searchTube search job by given search string in ready, delayed and buried
// stats.
func searchTube(server string, tube string, limit string, searchStr string) string {
func searchTube(server string, tube string, limit string, beanID string, state string, searchStr string) string {
var (
bstkConn *beanstalk.Conn
bstkConnStats map[string]string
err error
result = []SearchResult{}
searchLimit int
searchID uint64
statsFilter = []string{"ready", "delayed", "buried"}
table = currentTubeJobsSummaryTable(server, tube)
totalJobs, id uint64
Expand All @@ -290,24 +291,47 @@ func searchTube(server string, tube string, limit string, searchStr string) stri
if totalJobs, err = strconv.ParseUint(bstkConnStats["total-jobs"], 10, 64); err != nil {
return table
}
// Get ready stat job total
for _, state := range statsFilter {
var cnt int
for id = totalJobs; id > 0; id-- {
if cnt >= searchLimit {
continue
}
ret := searchTubeInStats(tube, searchStr, state, bstkConn, id)
if ret != nil {
result = append(result, *ret)
cnt++
if beanID != "" {
searchID, err = strconv.ParseUint(beanID, 10, 64)
if err != nil {
return table
}
ret := searchTubeByID(tube, searchID, bstkConn)
if ret != nil {
result = append(result, *ret)
}
} else {
if state != "" {
ret := limitResults(tube, searchStr, state, searchLimit, id, totalJobs, bstkConn)
result = append(result, *ret...)
} else {
// Get ready stat job total
for _, state := range statsFilter {
ret := limitResults(tube, searchStr, state, searchLimit, id, totalJobs, bstkConn)
result = append(result, *ret...)
}
}
}
bstkConn.Close()
return table + currentTubeSearchResults(server, tube, limit, searchStr, result)
}

func limitResults(tube, searchStr, state string, searchLimit int, id, totalJobs uint64, bstkConn *beanstalk.Conn) *[]SearchResult {
var cnt int
var result = []SearchResult{}
for id = totalJobs; id > 0; id-- {
if cnt >= searchLimit {
continue
}
ret := searchTubeInStats(tube, searchStr, state, bstkConn, id)
if ret != nil {
result = append(result, *ret)
cnt++
}
}
return &result
}

// searchTubeInStats search job in tube by given stats.
func searchTubeInStats(tube, searchStr, stat string, bstkConn *beanstalk.Conn, id uint64) *SearchResult {
jobStats, err := bstkConn.StatsJob(id)
Expand All @@ -331,3 +355,22 @@ func searchTubeInStats(tube, searchStr, stat string, bstkConn *beanstalk.Conn, i
Data: string(readyBody),
}
}

func searchTubeByID(tube string, searchID uint64, bstkConn *beanstalk.Conn) *SearchResult {
jobStats, err := bstkConn.StatsJob(searchID)
if err != nil {
return nil
}
if jobStats["tube"] != tube {
return nil
}
readyBody, err := bstkConn.Peek(searchID)
if err != nil {
return nil
}
return &SearchResult{
ID: searchID,
State: jobStats["state"],
Data: string(readyBody),
}
}
16 changes: 12 additions & 4 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ enabled = true
username = "admin"

[sample]
storage = "{\"jobs\":[{\"key\":\"97ec882fd75855dfa1b4bd00d4a367d4\",\"name\":\"sample_1\",\"tubes\":[\"default\"],\"data\":\"aurora_test_sample_job\",\"ttr\":60},{\"key\":\"d44782912092260cec11275b73f78434\",\"name\":\"sample_2\",\"tubes\":[\"aurora_test\"],\"data\":\"aurora_test_sample_job\",\"ttr\":60},{\"key\":\"5def7a2daf5e0292bed42db9f0017c94\",\"name\":\"sample_3\",\"tubes\":[\"default\",\"aurora_test\"],\"data\":\"aurora_test_sample_job\",\"ttr\":60}],\"tubes\":[{\"name\":\"default\",\"keys\":[\"97ec882fd75855dfa1b4bd00d4a367d4\",\"5def7a2daf5e0292bed42db9f0017c94\"]},{\"name\":\"aurora_test\",\"keys\":[\"d44782912092260cec11275b73f78434\",\"5def7a2daf5e0292bed42db9f0017c94\"]}]}"`
storage = "{\"jobs\":[{\"id\": 1, \"state\": ready, \"key\":\"97ec882fd75855dfa1b4bd00d4a367d4\",\"name\":\"sample_1\",\"tubes\":[\"default\"],\"data\":\"aurora_test_sample_job\",\"ttr\":60},{\"id\": 2, \"state\": ready, \"key\":\"d44782912092260cec11275b73f78434\",\"name\":\"sample_2\",\"tubes\":[\"aurora_test\"],\"data\":\"aurora_test_sample_job\",\"ttr\":60},{\"id\": 3, \"state\": ready, \"key\":\"5def7a2daf5e0292bed42db9f0017c94\",\"name\":\"sample_3\",\"tubes\":[\"default\",\"aurora_test\"],\"data\":\"aurora_test_sample_job\",\"ttr\":60}],\"tubes\":[{\"name\":\"default\",\"keys\":[\"97ec882fd75855dfa1b4bd00d4a367d4\",\"5def7a2daf5e0292bed42db9f0017c94\"]},{\"name\":\"aurora_test\",\"keys\":[\"d44782912092260cec11275b73f78434\",\"5def7a2daf5e0292bed42db9f0017c94\"]}]}"`
)

var (
Expand All @@ -53,7 +53,10 @@ var (
"/tube?server=" + bstk + "&tube=default&state=ready&action=kickJob&jobid=badID", // Kick job by given ID with no exits ID
"/tube?server=not_exist_server_addr&tube=default&state=ready&action=kickJob&jobid=1", // Kick job by given ID with no exits server
"/tube?server=" + bstk + "&tube=default&action=loadSample&key=97ec882fd75855dfa1b4bd00d4a367d4&redirect=tube&action=manageSamples", // Load sample job by given key
"/tube?server=" + bstk + "&tube=aurora_test&state=&action=search&limit=25&searchStr=t", // Search job
"/tube?server=" + bstk + "&tube=aurora_test&state=&action=search&limit=25&searchStr=t&id=", // Search job
"/tube?server=" + bstk + "&tube=aurora_test&state=delayed&action=search&limit=25&searchStr=t&id=", // Search job by state
"/tube?server=" + bstk + "&tube=aurora_test&state=&action=search&limit=25&searchStr=t&id=1", // Search job by id
"/tube?server=" + bstk + "&tube=aurora_test&state=&action=search&limit=25&searchStr=t&id=test", // Search job by id that is not number
"/tube?server=" + bstk + "&tube=aurora_test&state=&action=search&limit=25&searchStr=match", // Search job with not match string
"/tube?server=" + bstk + "&tube=aurora_test&action=moveJobsTo&destState=buried&state=ready", // Move job from ready to buried state
"/tube?server=not_exist_server_addr&tube=aurora_test&action=moveJobsTo&destState=buried&state=ready", // Move job from ready to buried state with no exits server
Expand Down Expand Up @@ -296,8 +299,13 @@ func TestMoveReadyJobsTo(t *testing.T) {

func TestSearchTube(t *testing.T) {
once.Do(testSetup)
searchTube(bstk, `default`, `not_int`, `ready`)
searchTube(bstk, `aurora_test_2`, `1`, `ready`)
searchTube(bstk, `default`, `not_int`, ``, ``, `ready`)
searchTube(bstk, `aurora_test_2`, `1`, ``, ``, `ready`)
searchTube(bstk, `aurora_test`, `1`, `not_int`, ``, `ready`)
searchTube(bstk, `aurora_test`, `1`, `1`, ``, `ready`)
searchTube(bstk, `aurora_test`, `1`, `100`, ``, `ready`)
searchTube(bstk, `aurora_test`, `1`, ``, `delayed`, `ready`)
searchTube(bstk, `aurora_test`, `1`, ``, `ready`, `ready`)
}

func TestAddSample(t *testing.T) {
Expand Down
7 changes: 4 additions & 3 deletions tplSearchTube.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ func tplSearchTube(server string, tube string, state string) string {
buf.WriteString(server)
buf.WriteString(`"/><input type="hidden" name="tube" value="`)
buf.WriteString(tube)
buf.WriteString(`"/><input type="hidden" name="state" value="`)
buf.WriteString(state)
buf.WriteString(`"/><input type="hidden" name="action" value="search"/><input type="hidden" name="limit" value="`)
buf.WriteString(strconv.Itoa(selfConf.SearchResultLimit))
buf.WriteString(`"/><div class="form-group"><input type="text" class="form-control input-sm search-query" name="searchStr" placeholder="Search this tube"></div></form>`)
buf.WriteString(`"/><div class="form-group"><select class="form-control input-sm search-query" style="margin-right: 10px;" id="state" name="state"><option value="" disabled selected>Select state</option><option>ready</option><option>delayed</option><option>buried</option></select>`)
buf.WriteString(`<input type="text" class="form-control input-sm search-query" style="margin-right: 10px;" name="id" placeholder="Bean ID"/>`)
buf.WriteString(`<input type="text" class="form-control input-sm search-query" style="margin-right: 10px;" name="searchStr" placeholder="Search this tube"/>`)
buf.WriteString(`<button type="submit" class="btn btn-info btn-sm">Search</button></div></form>`)
return buf.String()
}