Skip to content

Commit f94764d

Browse files
committed
feat: optimize api
1 parent 4a21b08 commit f94764d

14 files changed

+181
-118
lines changed

.vscode/launch.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@
5656
"program": "./cli/main.go",
5757
"args": ["server", "--config", "./config.json"],
5858
"cwd": "${workspaceFolder}",
59+
"env": {
60+
"DEBUG_DELAY": "1s"
61+
}
5962
},
6063
]
6164
}

api/debug/pprof.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
package debug
22

33
import (
4-
"github.com/semaphoreui/semaphore/util"
5-
log "github.com/sirupsen/logrus"
64
"net/http"
75
"os"
86
"path"
97
"runtime/pprof"
108
"strconv"
119
"time"
10+
11+
"github.com/semaphoreui/semaphore/util"
12+
log "github.com/sirupsen/logrus"
1213
)
1314

1415
func Dump(w http.ResponseWriter, r *http.Request) {
16+
if util.Config.Debugging.PprofDumpDir == "" {
17+
w.WriteHeader(http.StatusBadRequest)
18+
return
19+
}
1520

16-
f, err := os.Create(path.Join(util.Config.Profiling.DumpsDir, "mem-"+strconv.Itoa(int(time.Now().Unix()))+".prof"))
17-
18-
defer f.Close()
21+
f, err := os.Create(path.Join(util.Config.Debugging.PprofDumpDir, "mem-"+strconv.Itoa(int(time.Now().Unix()))+".prof"))
1922

2023
if err != nil {
2124
log.WithError(err).WithFields(log.Fields{
@@ -25,6 +28,8 @@ func Dump(w http.ResponseWriter, r *http.Request) {
2528
return
2629
}
2730

31+
defer f.Close()
32+
2833
err = pprof.WriteHeapProfile(f)
2934

3035
if err != nil {

api/helpers/helpers.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ import (
44
"encoding/json"
55
"errors"
66
"fmt"
7-
"github.com/semaphoreui/semaphore/services/tasks"
87
"net/http"
98
"net/url"
109
"runtime/debug"
1110
"slices"
1211
"strconv"
1312
"strings"
1413

14+
"github.com/semaphoreui/semaphore/services/tasks"
15+
1516
"github.com/gorilla/context"
1617
log "github.com/sirupsen/logrus"
1718

api/helpers/helpers_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,26 @@ package helpers
33
import (
44
"net/http"
55
"net/http/httptest"
6+
"os"
67
"testing"
8+
"time"
79

810
"github.com/gorilla/mux"
911
)
1012

13+
// SetTestDelay sets a delay for testing slow network conditions
14+
func SetTestDelay(delay time.Duration) func() {
15+
originalDelay := os.Getenv("DEBUG_DELAY")
16+
os.Setenv("DEBUG_DELAY", delay.String())
17+
return func() {
18+
if originalDelay == "" {
19+
os.Unsetenv("DEBUG_DELAY")
20+
} else {
21+
os.Setenv("DEBUG_DELAY", originalDelay)
22+
}
23+
}
24+
}
25+
1126
func TestGetIntParam(t *testing.T) {
1227
req, _ := http.NewRequest("GET", "/test/123", nil)
1328
rr := httptest.NewRecorder()

api/router.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ import (
44
"bytes"
55
"embed"
66
"fmt"
7-
"github.com/semaphoreui/semaphore/api/debug"
8-
"github.com/semaphoreui/semaphore/pkg/tz"
97
"net/http"
108
"os"
119
"path"
1210
"strings"
1311
"time"
1412

13+
"github.com/semaphoreui/semaphore/api/debug"
14+
"github.com/semaphoreui/semaphore/pkg/tz"
15+
log "github.com/sirupsen/logrus"
16+
1517
"github.com/semaphoreui/semaphore/api/runners"
1618

1719
"github.com/gorilla/mux"
@@ -61,11 +63,31 @@ func pongHandler(w http.ResponseWriter, r *http.Request) {
6163
w.Write([]byte("pong"))
6264
}
6365

66+
// DelayMiddleware adds artificial delay to simulate slow network conditions
67+
func DelayMiddleware(delay time.Duration) func(http.Handler) http.Handler {
68+
return func(next http.Handler) http.Handler {
69+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
70+
time.Sleep(delay)
71+
next.ServeHTTP(w, r)
72+
})
73+
}
74+
}
75+
6476
// Route declares all routes
6577
func Route() *mux.Router {
6678
r := mux.NewRouter()
6779
r.NotFoundHandler = http.HandlerFunc(servePublic)
6880

81+
if util.Config.Debugging.ApiDelay != "" {
82+
delay, err := time.ParseDuration(util.Config.Debugging.ApiDelay)
83+
if err != nil {
84+
log.WithError(err).WithFields(log.Fields{
85+
"context": "debugging",
86+
}).Panic("Invalid API delay format")
87+
}
88+
r.Use(DelayMiddleware(delay))
89+
}
90+
6991
webPath := "/"
7092
if util.WebHostURL != nil {
7193
webPath = util.WebHostURL.Path

db/Task.go

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import (
44
"encoding/json"
55
"errors"
66
"fmt"
7-
"github.com/semaphoreui/semaphore/pkg/tz"
87
"time"
98

9+
"github.com/semaphoreui/semaphore/pkg/tz"
10+
1011
"github.com/go-gorp/gorp/v3"
1112

1213
"github.com/semaphoreui/semaphore/pkg/task_logger"
@@ -44,35 +45,35 @@ type Task struct {
4445

4546
// override variables
4647
Playbook string `db:"playbook" json:"playbook"`
47-
Environment string `db:"environment" json:"environment"`
48-
Secret string `db:"-" json:"secret"`
49-
Arguments *string `db:"arguments" json:"arguments"`
50-
GitBranch *string `db:"git_branch" json:"git_branch"`
48+
Environment string `db:"environment" json:"environment,omitempty"`
49+
Secret string `db:"-" json:"secret,omitempty"`
50+
Arguments *string `db:"arguments" json:"arguments,omitempty"`
51+
GitBranch *string `db:"git_branch" json:"git_branch,omitempty"`
5152

52-
UserID *int `db:"user_id" json:"user_id"`
53-
IntegrationID *int `db:"integration_id" json:"integration_id"`
54-
ScheduleID *int `db:"schedule_id" json:"schedule_id"`
53+
UserID *int `db:"user_id" json:"user_id,omitempty"`
54+
IntegrationID *int `db:"integration_id" json:"integration_id,omitempty"`
55+
ScheduleID *int `db:"schedule_id" json:"schedule_id,omitempty"`
5556

5657
Created time.Time `db:"created" json:"created"`
57-
Start *time.Time `db:"start" json:"start"`
58-
End *time.Time `db:"end" json:"end"`
58+
Start *time.Time `db:"start" json:"start,omitempty"`
59+
End *time.Time `db:"end" json:"end,omitempty"`
5960

60-
Message string `db:"message" json:"message"`
61+
Message string `db:"message" json:"message,omitempty"`
6162

6263
// CommitMessage is a git commit hash of playbook repository which
6364
// was active when task was created.
64-
CommitHash *string `db:"commit_hash" json:"commit_hash"`
65+
CommitHash *string `db:"commit_hash" json:"commit_hash,omitempty"`
6566
// CommitMessage contains message retrieved from git repository after checkout to CommitHash.
6667
// It is readonly by API.
67-
CommitMessage string `db:"commit_message" json:"commit_message"`
68-
BuildTaskID *int `db:"build_task_id" json:"build_task_id"`
68+
CommitMessage string `db:"commit_message" json:"commit_message,omitempty"`
69+
BuildTaskID *int `db:"build_task_id" json:"build_task_id,omitempty"`
6970
// Version is a build version.
7071
// This field available only for Build tasks.
71-
Version *string `db:"version" json:"version"`
72+
Version *string `db:"version" json:"version,omitempty"`
7273

73-
InventoryID *int `db:"inventory_id" json:"inventory_id"`
74+
InventoryID *int `db:"inventory_id" json:"inventory_id,omitempty"`
7475

75-
Params MapStringAnyField `db:"params" json:"params"`
76+
Params MapStringAnyField `db:"params" json:"params,omitempty"`
7677
}
7778

7879
func (task *Task) FillParams(target interface{}) (err error) {
@@ -169,10 +170,10 @@ type TaskWithTpl struct {
169170
Task
170171
TemplatePlaybook string `db:"tpl_playbook" json:"tpl_playbook"`
171172
TemplateAlias string `db:"tpl_alias" json:"tpl_alias"`
172-
TemplateType TemplateType `db:"tpl_type" json:"tpl_type"`
173-
TemplateApp TemplateApp `db:"tpl_app" json:"tpl_app"`
174-
UserName *string `db:"user_name" json:"user_name"`
175-
BuildTask *Task `db:"-" json:"build_task"`
173+
TemplateType TemplateType `db:"tpl_type" json:"tpl_type,omitempty"`
174+
TemplateApp TemplateApp `db:"tpl_app" json:"tpl_app,omitempty"`
175+
UserName *string `db:"user_name" json:"user_name,omitempty"`
176+
BuildTask *Task `db:"-" json:"build_task,omitempty"`
176177
}
177178

178179
// TaskOutput is the ansible log output from the task

db/Template.go

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -105,53 +105,53 @@ type Template struct {
105105
ID int `db:"id" json:"id" backup:"-"`
106106

107107
ProjectID int `db:"project_id" json:"project_id" backup:"-"`
108-
InventoryID *int `db:"inventory_id" json:"inventory_id" backup:"-"`
108+
InventoryID *int `db:"inventory_id" json:"inventory_id,omitempty" backup:"-"`
109109
RepositoryID int `db:"repository_id" json:"repository_id" backup:"-"`
110-
EnvironmentID *int `db:"environment_id" json:"environment_id" backup:"-"`
110+
EnvironmentID *int `db:"environment_id" json:"environment_id,omitempty" backup:"-"`
111111

112112
// Name as described in https://github.com/semaphoreui/semaphore/issues/188
113113
Name string `db:"name" json:"name"`
114114
// playbook name in the form of "some_play.yml"
115115
Playbook string `db:"playbook" json:"playbook"`
116116
// to fit into []string
117-
Arguments *string `db:"arguments" json:"arguments"`
117+
Arguments *string `db:"arguments" json:"arguments,omitempty"`
118118
// if true, semaphore will not prepend any arguments to `arguments` like inventory, etc
119-
AllowOverrideArgsInTask bool `db:"allow_override_args_in_task" json:"allow_override_args_in_task"`
119+
AllowOverrideArgsInTask bool `db:"allow_override_args_in_task" json:"allow_override_args_in_task,omitempty"`
120120

121-
Description *string `db:"description" json:"description"`
121+
Description *string `db:"description" json:"description,omitempty"`
122122

123-
Vaults []TemplateVault `db:"-" json:"vaults" backup:"-"`
123+
Vaults []TemplateVault `db:"-" json:"vaults,omitempty" backup:"-"`
124124

125-
Type TemplateType `db:"type" json:"type"`
126-
StartVersion *string `db:"start_version" json:"start_version"`
127-
BuildTemplateID *int `db:"build_template_id" json:"build_template_id" backup:"-"`
125+
Type TemplateType `db:"type" json:"type,omitempty"`
126+
StartVersion *string `db:"start_version" json:"start_version,omitempty"`
127+
BuildTemplateID *int `db:"build_template_id" json:"build_template_id,omitempty" backup:"-"`
128128

129-
ViewID *int `db:"view_id" json:"view_id" backup:"-"`
129+
ViewID *int `db:"view_id" json:"view_id,omitempty" backup:"-"`
130130

131-
LastTask *TaskWithTpl `db:"-" json:"last_task" backup:"-"`
131+
LastTask *TaskWithTpl `db:"-" json:"last_task,omitempty" backup:"-"`
132132

133-
Autorun bool `db:"autorun" json:"autorun"`
133+
Autorun bool `db:"autorun" json:"autorun,omitempty"`
134134

135135
// override variables
136-
GitBranch *string `db:"git_branch" json:"git_branch"`
136+
GitBranch *string `db:"git_branch" json:"git_branch,omitempty"`
137137

138138
// SurveyVarsJSON used internally for read from database.
139139
// It is not used for store survey vars to database.
140140
// Do not use it in your code. Use SurveyVars instead.
141141
SurveyVarsJSON *string `db:"survey_vars" json:"-" backup:"-"`
142-
SurveyVars []SurveyVar `db:"-" json:"survey_vars" backup:"survey_vars"`
142+
SurveyVars []SurveyVar `db:"-" json:"survey_vars,omitempty" backup:"survey_vars"`
143143

144-
SuppressSuccessAlerts bool `db:"suppress_success_alerts" json:"suppress_success_alerts"`
144+
SuppressSuccessAlerts bool `db:"suppress_success_alerts" json:"suppress_success_alerts,omitempty"`
145145

146-
App TemplateApp `db:"app" json:"app"`
146+
App TemplateApp `db:"app" json:"app,omitempty"`
147147

148148
Tasks int `db:"tasks" json:"tasks" backup:"-"`
149149

150-
TaskParams MapStringAnyField `db:"task_params" json:"task_params"`
150+
TaskParams MapStringAnyField `db:"task_params" json:"task_params,omitempty"`
151151

152-
RunnerTag *string `db:"runner_tag" json:"runner_tag"`
152+
RunnerTag *string `db:"runner_tag" json:"runner_tag,omitempty"`
153153

154-
AllowOverrideBranchInTask bool `db:"allow_override_branch_in_task" json:"allow_override_branch_in_task"`
154+
AllowOverrideBranchInTask bool `db:"allow_override_branch_in_task" json:"allow_override_branch_in_task,omitempty"`
155155
}
156156

157157
func (tpl *Template) FillParams(target interface{}) error {

db/TemplateVault.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ type TemplateVault struct {
1111
ID int `db:"id" json:"id" backup:"-"`
1212
ProjectID int `db:"project_id" json:"project_id" backup:"-"`
1313
TemplateID int `db:"template_id" json:"template_id" backup:"-"`
14-
VaultKeyID *int `db:"vault_key_id" json:"vault_key_id" backup:"-"`
15-
Name *string `db:"name" json:"name"`
14+
VaultKeyID *int `db:"vault_key_id" json:"vault_key_id,omitempty" backup:"-"`
15+
Name *string `db:"name" json:"name,omitempty"`
1616
Type TemplateVaultType `db:"type" json:"type"`
17-
Script *string `db:"script" json:"script"`
17+
Script *string `db:"script" json:"script,omitempty"`
1818

1919
Vault *AccessKey `db:"-" json:"-"`
2020
}

db/sql/template.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package sql
22

33
import (
44
"encoding/json"
5+
56
"github.com/Masterminds/squirrel"
67
"github.com/semaphoreui/semaphore/db"
78
)
@@ -183,6 +184,7 @@ func (d *SqlDb) GetTemplates(projectID int, filter db.TemplateFilter, params db.
183184
"pt.`type`",
184185
"pt.`tasks`",
185186
"pt.runner_tag",
187+
"pt.task_params",
186188
"pt.allow_override_branch_in_task",
187189
"(SELECT `id` FROM `task` WHERE template_id = pt.id ORDER BY `id` DESC LIMIT 1) last_task_id").
188190
From("project__template pt")

util/config.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ import (
88
"encoding/json"
99
"errors"
1010
"fmt"
11-
"github.com/semaphoreui/semaphore/pkg/task_logger"
12-
"golang.org/x/crypto/bcrypt"
13-
"gopkg.in/natefinch/lumberjack.v2"
1411
"io"
1512
"net/url"
1613
"os"
@@ -22,6 +19,10 @@ import (
2219
"strconv"
2320
"strings"
2421

22+
"github.com/semaphoreui/semaphore/pkg/task_logger"
23+
"golang.org/x/crypto/bcrypt"
24+
"gopkg.in/natefinch/lumberjack.v2"
25+
2526
"github.com/google/go-github/github"
2627
"github.com/gorilla/securecookie"
2728
)
@@ -207,9 +208,9 @@ type ScheduleConfig struct {
207208
Timezone string `json:"timezone,omitempty" env:"SEMAPHORE_SCHEDULE_TIMEZONE" default:"UTC"`
208209
}
209210

210-
type ProfilingConfig struct {
211-
Enabled bool `json:"enabled,omitempty" env:"SEMAPHORE_PROFILING_ENABLED"`
212-
DumpsDir string `json:"dumps_dir,omitempty" env:"SEMAPHORE_PROFILING_DUMPS_DIR" default:"/tmp/semaphore/profiler"`
211+
type DebuggingConfig struct {
212+
ApiDelay string `json:"api_delay,omitempty" env:"SEMAPHORE_API_DELAY"`
213+
PprofDumpDir string `json:"pprof_dump_dir,omitempty" env:"SEMAPHORE_PPROF_DUMP_DIR"`
213214
}
214215

215216
// ConfigType mapping between Config and the json file that sets it
@@ -320,7 +321,7 @@ type ConfigType struct {
320321

321322
Schedule *ScheduleConfig `json:"schedule,omitempty"`
322323

323-
Profiling *ProfilingConfig `json:"profiling,omitempty"`
324+
Debugging *DebuggingConfig `json:"debugging,omitempty"`
324325
}
325326

326327
func NewConfigType() *ConfigType {

0 commit comments

Comments
 (0)