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

feat: add refreshFrequency option for blocking strategy #461

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
9 changes: 5 additions & 4 deletions app/http/routes/models/blocking_request.go
Original file line number Diff line number Diff line change
@@ -3,8 +3,9 @@ package models
import "time"

type BlockingRequest struct {
Names []string `form:"names"`
Group string `form:"group"`
SessionDuration time.Duration `form:"session_duration"`
Timeout time.Duration `form:"timeout"`
Names []string `form:"names"`
Group string `form:"group"`
SessionDuration time.Duration `form:"session_duration"`
Timeout time.Duration `form:"timeout"`
RefreshFrequency time.Duration `form:"refresh_frequency"`
}
5 changes: 3 additions & 2 deletions app/http/routes/strategies.go
Original file line number Diff line number Diff line change
@@ -99,6 +99,7 @@ func (s *ServeStrategy) ServeDynamic(c *gin.Context) {
func (s *ServeStrategy) ServeBlocking(c *gin.Context) {
request := models.BlockingRequest{
Timeout: s.StrategyConfig.Blocking.DefaultTimeout,
RefreshFrequency: s.StrategyConfig.Blocking.DefaultRefreshFrequency,
}

if err := c.ShouldBind(&request); err != nil {
@@ -109,9 +110,9 @@ func (s *ServeStrategy) ServeBlocking(c *gin.Context) {
var sessionState *sessions.SessionState
var err error
if len(request.Names) > 0 {
sessionState, err = s.SessionsManager.RequestReadySession(c.Request.Context(), request.Names, request.SessionDuration, request.Timeout)
sessionState, err = s.SessionsManager.RequestReadySession(c.Request.Context(), request.Names, request.SessionDuration, request.Timeout, request.RefreshFrequency)
} else {
sessionState, err = s.SessionsManager.RequestReadySessionGroup(c.Request.Context(), request.Group, request.SessionDuration, request.Timeout)
sessionState, err = s.SessionsManager.RequestReadySessionGroup(c.Request.Context(), request.Group, request.SessionDuration, request.Timeout, request.RefreshFrequency)
}

if err != nil {
2 changes: 1 addition & 1 deletion app/http/routes/strategies_test.go
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ func (s *SessionsManagerMock) RequestSession(names []string, duration time.Durat
return &s.SessionState
}

func (s *SessionsManagerMock) RequestReadySession(ctx context.Context, names []string, duration time.Duration, timeout time.Duration) (*sessions.SessionState, error) {
func (s *SessionsManagerMock) RequestReadySession(ctx context.Context, names []string, duration time.Duration, timeout time.Duration, frequency time.Duration) (*sessions.SessionState, error) {
return &s.SessionState, nil
}

12 changes: 6 additions & 6 deletions app/sessions/sessions_manager.go
Original file line number Diff line number Diff line change
@@ -20,8 +20,8 @@ const defaultRefreshFrequency = 2 * time.Second
type Manager interface {
RequestSession(names []string, duration time.Duration) *SessionState
RequestSessionGroup(group string, duration time.Duration) *SessionState
RequestReadySession(ctx context.Context, names []string, duration time.Duration, timeout time.Duration) (*SessionState, error)
RequestReadySessionGroup(ctx context.Context, group string, duration time.Duration, timeout time.Duration) (*SessionState, error)
RequestReadySession(ctx context.Context, names []string, duration time.Duration, timeout time.Duration, frequency time.Duration) (*SessionState, error)
RequestReadySessionGroup(ctx context.Context, group string, duration time.Duration, timeout time.Duration, frequency time.Duration) (*SessionState, error)

LoadSessions(io.ReadCloser) error
SaveSessions(io.WriteCloser) error
@@ -226,14 +226,14 @@ func (s *SessionsManager) requestSessionInstance(name string, duration time.Dura
return &requestState, nil
}

func (s *SessionsManager) RequestReadySession(ctx context.Context, names []string, duration time.Duration, timeout time.Duration) (*SessionState, error) {
func (s *SessionsManager) RequestReadySession(ctx context.Context, names []string, duration time.Duration, timeout time.Duration, frequency time.Duration) (*SessionState, error) {

session := s.RequestSession(names, duration)
if session.IsReady() {
return session, nil
}

ticker := time.NewTicker(5 * time.Second)
ticker := time.NewTicker(frequency)
readiness := make(chan *SessionState)
quit := make(chan struct{})

@@ -266,7 +266,7 @@ func (s *SessionsManager) RequestReadySession(ctx context.Context, names []strin
}
}

func (s *SessionsManager) RequestReadySessionGroup(ctx context.Context, group string, duration time.Duration, timeout time.Duration) (sessionState *SessionState, err error) {
func (s *SessionsManager) RequestReadySessionGroup(ctx context.Context, group string, duration time.Duration, timeout time.Duration, frequency time.Duration) (sessionState *SessionState, err error) {

if len(group) == 0 {
return nil, fmt.Errorf("group is mandatory")
@@ -278,7 +278,7 @@ func (s *SessionsManager) RequestReadySessionGroup(ctx context.Context, group st
return nil, fmt.Errorf("group has no member")
}

return s.RequestReadySession(ctx, names, duration, timeout)
return s.RequestReadySession(ctx, names, duration, timeout, frequency)
}

func (s *SessionsManager) ExpiresAfter(instance *instance.State, duration time.Duration) {
6 changes: 3 additions & 3 deletions app/sessions/sessions_manager_test.go
Original file line number Diff line number Diff line change
@@ -140,7 +140,7 @@ func TestSessionsManager_RequestReadySessionCancelledByUser(t *testing.T) {

errchan := make(chan error)
go func() {
_, err := s.RequestReadySession(ctx, []string{"nginx", "whoami"}, time.Minute, time.Minute)
_, err := s.RequestReadySession(ctx, []string{"nginx", "whoami"}, time.Minute, time.Minute, time.Second)
errchan <- err
}()

@@ -167,7 +167,7 @@ func TestSessionsManager_RequestReadySessionCancelledByTimeout(t *testing.T) {

errchan := make(chan error)
go func() {
_, err := s.RequestReadySession(context.Background(), []string{"nginx", "whoami"}, time.Minute, time.Second)
_, err := s.RequestReadySession(context.Background(), []string{"nginx", "whoami"}, time.Minute, time.Second, time.Second)
errchan <- err
}()

@@ -190,7 +190,7 @@ func TestSessionsManager_RequestReadySession(t *testing.T) {

errchan := make(chan error)
go func() {
_, err := s.RequestReadySession(context.Background(), []string{"nginx", "whoami"}, time.Minute, time.Second)
_, err := s.RequestReadySession(context.Background(), []string{"nginx", "whoami"}, time.Minute, time.Second, time.Second)
errchan <- err
}()

2 changes: 2 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -83,6 +83,8 @@ It provides an integrations with multiple reverse proxies and different loading
viper.BindPFlag("strategy.dynamic.default-refresh-frequency", startCmd.Flags().Lookup("strategy.dynamic.default-refresh-frequency"))
startCmd.Flags().DurationVar(&conf.Strategy.Blocking.DefaultTimeout, "strategy.blocking.default-timeout", 1*time.Minute, "Default timeout used for blocking strategy")
viper.BindPFlag("strategy.blocking.default-timeout", startCmd.Flags().Lookup("strategy.blocking.default-timeout"))
startCmd.Flags().DurationVar(&conf.Strategy.Blocking.DefaultRefreshFrequency, "strategy.blocking.default-refresh-frequency", 5*time.Second, "Default refresh frequency for blocking strategy")
viper.BindPFlag("strategy.blocking.default-refresh-frequency", startCmd.Flags().Lookup("strategy.blocking.default-refresh-frequency"))

rootCmd.AddCommand(startCmd)
rootCmd.AddCommand(newVersionCommand())
1 change: 1 addition & 0 deletions cmd/root_test.go
Original file line number Diff line number Diff line change
@@ -120,6 +120,7 @@ func TestPrecedence(t *testing.T) {
"--strategy.dynamic.default-theme", "cli",
"--strategy.dynamic.default-refresh-frequency", "3h",
"--strategy.blocking.default-timeout", "3h",
"--strategy.blocking.default-refresh-frequency", "3h",
})
cmd.Execute()

3 changes: 2 additions & 1 deletion cmd/testdata/config.env
Original file line number Diff line number Diff line change
@@ -13,4 +13,5 @@ STRATEGY_DYNAMIC_CUSTOM_THEMES_PATH=/tmp/envvar/themes
STRATEGY_SHOW_DETAILS_BY_DEFAULT=false
STRATEGY_DYNAMIC_DEFAULT_THEME=envvar
STRATEGY_DYNAMIC_DEFAULT_REFRESH_FREQUENCY=2h
STRATEGY_BLOCKING_DEFAULT_TIMEOUT=2h
STRATEGY_BLOCKING_DEFAULT_TIMEOUT=2h
STRATEGY_BLOCKING_DEFAULT_REFRESH_FREQUENCY=2h
3 changes: 2 additions & 1 deletion cmd/testdata/config.yml
Original file line number Diff line number Diff line change
@@ -22,4 +22,5 @@ strategy:
default-theme: configfile
default-refresh-frequency: 1h
blocking:
default-timeout: 1h
default-timeout: 1h
default-refresh-frequency: 1h
3 changes: 2 additions & 1 deletion cmd/testdata/config_cli_wanted.json
Original file line number Diff line number Diff line change
@@ -30,7 +30,8 @@
"DefaultRefreshFrequency": 10800000000000
},
"Blocking": {
"DefaultTimeout": 10800000000000
"DefaultTimeout": 10800000000000,
"DefaultRefreshFrequency": 10800000000000
}
}
}
3 changes: 2 additions & 1 deletion cmd/testdata/config_default.json
Original file line number Diff line number Diff line change
@@ -30,7 +30,8 @@
"DefaultRefreshFrequency": 5000000000
},
"Blocking": {
"DefaultTimeout": 60000000000
"DefaultTimeout": 60000000000,
"DefaultRefreshFrequency": 5000000000
}
}
}
3 changes: 2 additions & 1 deletion cmd/testdata/config_env_wanted.json
Original file line number Diff line number Diff line change
@@ -30,7 +30,8 @@
"DefaultRefreshFrequency": 7200000000000
},
"Blocking": {
"DefaultTimeout": 7200000000000
"DefaultTimeout": 7200000000000,
"DefaultRefreshFrequency": 7200000000000
}
}
}
3 changes: 2 additions & 1 deletion cmd/testdata/config_yaml_wanted.json
Original file line number Diff line number Diff line change
@@ -30,7 +30,8 @@
"DefaultRefreshFrequency": 3600000000000
},
"Blocking": {
"DefaultTimeout": 3600000000000
"DefaultTimeout": 3600000000000,
"DefaultRefreshFrequency": 3600000000000
}
}
}
3 changes: 2 additions & 1 deletion config/strategy.go
Original file line number Diff line number Diff line change
@@ -10,7 +10,8 @@ type DynamicStrategy struct {
}

type BlockingStrategy struct {
DefaultTimeout time.Duration `mapstructure:"DEFAULT_TIMEOUT" yaml:"defaultTimeout" default:"1m"`
DefaultTimeout time.Duration `mapstructure:"DEFAULT_TIMEOUT" yaml:"defaultTimeout" default:"1m"`
DefaultRefreshFrequency time.Duration `mapstructure:"DEFAULT_REFRESH_FREQUENCY" yaml:"defaultRefreshFrequency" default:"5s"`
}

type Strategy struct {
1 change: 1 addition & 0 deletions docs/plugins/caddy.md
Original file line number Diff line number Diff line change
@@ -62,6 +62,7 @@ You can have the following configuration:
}
blocking {
[timeout 1m]
[refresh_frequency 2s]
}
}
reverse_proxy myservice:port
36 changes: 21 additions & 15 deletions plugins/caddy/config.go
Original file line number Diff line number Diff line change
@@ -25,7 +25,8 @@ type DynamicConfiguration struct {
}

type BlockingConfiguration struct {
Timeout *time.Duration
Timeout *time.Duration
RefreshFrequency *time.Duration
}

type Config struct {
@@ -49,21 +50,20 @@ func CreateConfig() *Config {

// UnmarshalCaddyfile implements caddyfile.Unmarshaler. Syntax:
//
// sablier [<sablierURL>] {
// [names container1,container2,...]
// [group mygroup]
// [session_duration 30m]
// dynamic {
// [display_name This is my display name]
// [show_details yes|true|on]
// [theme hacker-terminal]
// [refresh_frequency 2s]
// }
// blocking {
// [timeout 1m]
// }
// sablier [<sablierURL>] {
// [names container1,container2,...]
// [group mygroup]
// [session_duration 30m]
// dynamic {
// [display_name This is my display name]
// [show_details yes|true|on]
// [theme hacker-terminal]
// [refresh_frequency 2s]
// }
//
// blocking {
// [timeout 1m]
// }
// }
func (c *Config) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() {
if d.NextArg() {
@@ -172,6 +172,12 @@ func parseBlocking(d *caddyfile.Dispenser) (*BlockingConfiguration, error) {
return nil, err
}
conf.Timeout = &duration
case "refresh_frequency":
duration, err := time.ParseDuration(args)
if err != nil {
return nil, err
}
conf.RefreshFrequency = &duration
}
}
return conf, nil
17 changes: 16 additions & 1 deletion plugins/caddy/config_test.go
Original file line number Diff line number Diff line change
@@ -183,6 +183,19 @@ func TestConfig_BuildRequest(t *testing.T) {
want: createRequest("GET", "http://sablier:10000/api/strategies/blocking?names=nginx&names=apache&session_duration=1m&timeout=5m", nil),
wantErr: false,
},
{
name: "blocking session with refresh frequency",
fields: caddy.Config{
SablierURL: "http://sablier:10000",
Names: []string{"nginx", "apache"},
SessionDuration: &oneMinute,
Dynamic: &caddy.DynamicConfiguration{
RefreshFrequency: &oneMinute,
},
},
want: createRequest("GET", "http://sablier:10000/api/strategies/blocking?names=nginx&names=apache&refresh_frequency=1m&session_duration=1m", nil),
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -296,14 +309,16 @@ func TestConfig_UnmarshalCaddyfile(t *testing.T) {
session_duration 1m
blocking {
timeout 1m
refresh_frequency 1m
}
}`,
want: caddy.Config{
SablierURL: "http://sablier:10000",
Group: "mygroup",
SessionDuration: &oneMinute,
Blocking: &caddy.BlockingConfiguration{
Timeout: &oneMinute,
Timeout: &oneMinute,
RefreshFrequency: &oneMinute,
},
},
wantErr: false,
35 changes: 18 additions & 17 deletions plugins/nginx/njs/sablier.js
Original file line number Diff line number Diff line change
@@ -30,12 +30,12 @@ function call(r) {
* @property {string} theme
* @property {string} refreshFrequency
* @property {string} timeout
*
*
*/

/**
*
* @param {*} headers
*
* @param {*} headers
* @returns {SablierConfig}
*/
function createConfigurationFromVariables(r) {
@@ -56,9 +56,9 @@ function createConfigurationFromVariables(r) {
}

/**
*
* @param {SablierConfig} c
* @returns
*
* @param {SablierConfig} c
* @returns
*/
function buildRequest(c) {
if (c.timeout == undefined || c.timeout == "") {
@@ -69,9 +69,9 @@ function buildRequest(c) {
}

/**
*
* @param {SablierConfig} config
* @returns
*
* @param {SablierConfig} config
* @returns
*/
function createDynamicUrl(config) {
const url = `${config.sablierUrl}/api/strategies/dynamic`
@@ -88,21 +88,22 @@ function buildRequest(c) {
} else if(config.group) {
query.group = config.group
} else {
throw new Error('you must specify names or group');
throw new Error('you must specify names or group');
}

return {url, query: querystring.stringify(query)}
}

/**
*
* @param {SablierConfig} config
* @returns
*
* @param {SablierConfig} config
* @returns
*/
function createBlockingUrl(config) {
const url = `${config.sablierUrl}/api/strategies/blocking`
const query = {
const query = {
session_duration: config.sessionDuration,
refresh_frequency: config.refreshFrequency,
timeout:config.timeout,
};

@@ -111,10 +112,10 @@ function buildRequest(c) {
} else if(config.group) {
query.group = config.group
} else {
throw new Error('you must specify names or group');
throw new Error('you must specify names or group');
}

return {url, query: querystring.stringify(query)}
return {url, query: querystring.stringify(query)}
}

export default { call };
export default { call };
13 changes: 12 additions & 1 deletion plugins/traefik/config.go
Original file line number Diff line number Diff line change
@@ -16,7 +16,8 @@ type DynamicConfiguration struct {
}

type BlockingConfiguration struct {
Timeout string `yaml:"timeout"`
Timeout string `yaml:"timeout"`
RefreshFrequency string `yaml:"refreshFrequency"`
}

type Config struct {
@@ -154,6 +155,16 @@ func (c *Config) buildBlockingRequest() (*http.Request, error) {
q.Add("session_duration", c.SessionDuration)
}

if c.Blocking.RefreshFrequency != "" {
_, err := time.ParseDuration(c.Dynamic.RefreshFrequency)

if err != nil {
return nil, fmt.Errorf("error parsing dynamic.refreshFrequency: %v", err)
}

q.Add("refresh_frequency", c.Dynamic.RefreshFrequency)
}

for _, name := range c.splittedNames {
q.Add("names", name)
}
3 changes: 2 additions & 1 deletion sablier.sample.yaml
Original file line number Diff line number Diff line change
@@ -17,4 +17,5 @@ strategy:
default-theme: hacker-terminal
default-refresh-frequency: 5s
blocking:
default-timeout: 1m
default-timeout: 1m
default-refresh-frequency: 5s