From 59d79e9b60da555b0233c65aa678085ef1532793 Mon Sep 17 00:00:00 2001 From: Paul Lorenz Date: Thu, 14 Dec 2023 13:24:37 -0500 Subject: [PATCH 1/2] Do fewer session refreshes. Fixes #468 --- CHANGELOG.md | 4 ++++ version | 2 +- ziti/options.go | 15 ++++++++++-- ziti/ziti.go | 61 ++++++++++++++++++++++++++++++++++--------------- 4 files changed, 60 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cc1160d..2876def6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# Release 0.22.0 + +- Add SessionRefreshInterval to DialOptions, with a default of 1 hour. + # Release 0.21.0 - New `ListenOptions` field: `WaitForNEstablishedListeners`. Allows specifying that you want at least N listeners to be established before the `Listen` method returns. Defaults to 0. diff --git a/version b/version index 5320adc1..e3462940 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.21 +0.22 diff --git a/ziti/options.go b/ziti/options.go index 5c2d003e..006dbb77 100644 --- a/ziti/options.go +++ b/ziti/options.go @@ -11,13 +11,23 @@ const ( ServiceAdded ServiceEventType = "Added" ServiceRemoved ServiceEventType = "Removed" ServiceChanged ServiceEventType = "Changed" + + DefaultServiceRefreshInterval = 5 * time.Minute + DefaultSessionRefreshInterval = time.Hour ) type serviceCB func(eventType ServiceEventType, service *rest_model.ServiceDetail) type Options struct { + // Service refresh interval. May not be less than 1 second RefreshInterval time.Duration + // Edge session refresh interval. Edge session only need to be refreshed if the list of available + // edge routers has changed. This should be a relatively rare occurrence. If a dial fails, the + // edge session will be refreshed regardless. + // May not be less than 1 second + SessionRefreshInterval time.Duration + // Deprecated: OnContextReady is a callback that is invoked after the first successful authentication request. It // does not delineate between fully and partially authenticated API Sessions. Use context.AddListener() with the events // EventAuthenticationStateFull, EventAuthenticationStatePartial, EventAuthenticationStateUnAuthenticated instead. @@ -34,8 +44,9 @@ func (self *Options) isEdgeRouterUrlAccepted(url string) bool { } var DefaultOptions = &Options{ - RefreshInterval: 5 * time.Minute, - OnServiceUpdate: nil, + RefreshInterval: DefaultServiceRefreshInterval, + SessionRefreshInterval: DefaultSessionRefreshInterval, + OnServiceUpdate: nil, } type DialOptions struct { diff --git a/ziti/ziti.go b/ziti/ziti.go index 3e16c5a9..9c84cd38 100644 --- a/ziti/ziti.go +++ b/ziti/ziti.go @@ -710,10 +710,29 @@ func (context *ContextImpl) RefreshService(serviceName string) (*rest_model.Serv return serviceDetail, nil } -func (context *ContextImpl) runSessionRefresh() { +func (context *ContextImpl) runRefreshes() { log := pfxlog.Logger() - svcUpdateTick := time.NewTicker(context.options.RefreshInterval) - defer svcUpdateTick.Stop() + svcRefreshInterval := context.options.RefreshInterval + + if svcRefreshInterval == 0 { + svcRefreshInterval = DefaultServiceRefreshInterval + } + if svcRefreshInterval < time.Second { + svcRefreshInterval = time.Second + } + svcRefreshTick := time.NewTicker(svcRefreshInterval) + defer svcRefreshTick.Stop() + + sessionRefreshInterval := context.options.SessionRefreshInterval + if sessionRefreshInterval == 0 { + sessionRefreshInterval = DefaultSessionRefreshInterval + } + if sessionRefreshInterval < time.Second { + sessionRefreshInterval = time.Second + } + + sessionRefreshTick := time.NewTicker(sessionRefreshInterval) + defer sessionRefreshTick.Stop() refreshAt := time.Now().Add(30 * time.Second) if currentApiSession := context.CtrlClt.GetCurrentApiSession(); currentApiSession != nil && currentApiSession.ExpiresAt != nil { @@ -736,13 +755,15 @@ func (context *ContextImpl) runSessionRefresh() { log.Debugf("apiSession refreshed, new expiration[%s]", *exp) } - case <-svcUpdateTick.C: + case <-svcRefreshTick.C: log.Debug("refreshing services") if err := context.refreshServices(false); err != nil { log.WithError(err).Error("failed to load service updates") - } else { - context.refreshSessions() } + + case <-sessionRefreshTick.C: + log.Debug("refreshing sessions") + context.refreshSessions() } } } @@ -853,7 +874,7 @@ func (context *ContextImpl) onFullAuth(apiSession *rest_model.CurrentAPISessionD if context.options.OnContextReady != nil { context.options.OnContextReady(context) } - go context.runSessionRefresh() + go context.runRefreshes() metricsTags := map[string]string{ "srcId": apiSession.Identity.ID, @@ -1110,20 +1131,22 @@ func (context *ContextImpl) listenSession(service *rest_model.ServiceDetail, opt func (context *ContextImpl) getEdgeRouterConn(session *rest_model.SessionDetail, options edge.ConnOptions) (edge.RouterConn, error) { logger := pfxlog.Logger().WithField("sessionId", *session.ID) - if refreshedSession, err := context.refreshSession(*session.ID); err != nil { - target := &rest_session.DetailSessionNotFound{} - if errors.As(err, &target) { - sessionKey := fmt.Sprintf("%s:%s", session.Service.ID, *session.Type) - context.sessions.Remove(sessionKey) - } + if len(session.EdgeRouters) == 0 { + if refreshedSession, err := context.refreshSession(*session.ID); err != nil { + target := &rest_session.DetailSessionNotFound{} + if errors.As(err, &target) { + sessionKey := fmt.Sprintf("%s:%s", session.Service.ID, *session.Type) + context.sessions.Remove(sessionKey) + } - return nil, fmt.Errorf("no edge routers available, refresh errored: %v", err) - } else { - if len(refreshedSession.EdgeRouters) == 0 { - return nil, errors.New("no edge routers available, refresh yielded no new edge routers") - } + return nil, fmt.Errorf("no edge routers available, refresh errored: %v", err) + } else { + if len(refreshedSession.EdgeRouters) == 0 { + return nil, errors.New("no edge routers available, refresh yielded no new edge routers") + } - session = refreshedSession + session = refreshedSession + } } // go through connected routers first From 85ccf589bb7406a0457ec2287d03e79b2a41d81a Mon Sep 17 00:00:00 2001 From: Paul Lorenz Date: Thu, 14 Dec 2023 16:49:59 -0500 Subject: [PATCH 2/2] Add constant for min refresh interval --- ziti/options.go | 1 + ziti/ziti.go | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ziti/options.go b/ziti/options.go index 006dbb77..36883144 100644 --- a/ziti/options.go +++ b/ziti/options.go @@ -14,6 +14,7 @@ const ( DefaultServiceRefreshInterval = 5 * time.Minute DefaultSessionRefreshInterval = time.Hour + MinRefreshInterval = time.Second ) type serviceCB func(eventType ServiceEventType, service *rest_model.ServiceDetail) diff --git a/ziti/ziti.go b/ziti/ziti.go index 9c84cd38..8c095dd4 100644 --- a/ziti/ziti.go +++ b/ziti/ziti.go @@ -717,8 +717,8 @@ func (context *ContextImpl) runRefreshes() { if svcRefreshInterval == 0 { svcRefreshInterval = DefaultServiceRefreshInterval } - if svcRefreshInterval < time.Second { - svcRefreshInterval = time.Second + if svcRefreshInterval < MinRefreshInterval { + svcRefreshInterval = MinRefreshInterval } svcRefreshTick := time.NewTicker(svcRefreshInterval) defer svcRefreshTick.Stop() @@ -727,8 +727,8 @@ func (context *ContextImpl) runRefreshes() { if sessionRefreshInterval == 0 { sessionRefreshInterval = DefaultSessionRefreshInterval } - if sessionRefreshInterval < time.Second { - sessionRefreshInterval = time.Second + if sessionRefreshInterval < MinRefreshInterval { + sessionRefreshInterval = MinRefreshInterval } sessionRefreshTick := time.NewTicker(sessionRefreshInterval)