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

Gracefully shutdown analytics module/runner #3335

Merged

Conversation

zhongshixi
Copy link
Contributor

@zhongshixi zhongshixi commented Dec 5, 2023

Problem

  1. I have an implementation of an adapter that requires explicit flushing of the data when the prebid server shutdown to ensure minimum data loss and I would like not to duplicate the signal notification logic written in the server listener.

Solution

  1. I think the best solution is to provide a common interface Shutdown() so different analytic module could implement their own way of shutting down their module, if a module does not require a graceful shutdown, then just provide no-op implementation

@zhongshixi zhongshixi changed the title graceful shutdown of the analytic module/runner graceful shutdown for the analytic module/runner Dec 5, 2023
@bsardo bsardo changed the title graceful shutdown for the analytic module/runner Gracefully shutdown analytics module/runner Dec 6, 2023
Comment on lines +95 to +136
func (ea enabledAnalytics) Shutdown() {
for _, module := range ea {
module.Shutdown()
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code block isn't covered by tests, can you update this?

router/router.go Outdated

analyticsRunner := analyticsBuild.New(&cfg.Analytics)

// todo(zachbadgett): better shutdown
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this TODO be removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i did not remove this because i do not have context of TODO - is it okay to remove this line ? @zachbadgett

Copy link
Contributor Author

@zhongshixi zhongshixi Apr 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i will just remove it - i think i figured out what is a better shutdown

router/router.go Outdated
Comment on lines 207 to 210
r.Shutdown = func() {
shutdown()
analyticsRunner.Shutdown()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to cover this code with tests? I know a lot of code in this file is uncovered already, so no worries if not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let me see what i can do

Copy link
Contributor Author

@zhongshixi zhongshixi Apr 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it might work, but requires a big refactoring effort, as the router itself is not fully dependency inverted - that means i have to figure out how to pass a proper mock to test this function early.

ideally, i think we should apply dependency inversion pattern to the initialization process of the router to make it easier to test.

cc @bsardo
let me know if you think it is necessary as part of the PR to start invert analytic runner and storedRequestsConf.NewStoredRequests or we should do full dependency inversion as the prebid server 3.0 ( i am all in refactoring the code for better design pattern )

@@ -85,6 +85,9 @@ func (f *FileLogger) LogNotificationEventObject(ne *analytics.NotificationEvent)
f.Logger.Flush()
}

// Shutdown the logger - No-op Implementation
func (f *FileLogger) Shutdown() {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we call flush in order to output all pending buffered data just in case there's any?

88   // Shutdown the logger - No-op Implementation
89 - func (f *FileLogger) Shutdown() {}
   + func (f *FileLogger) Shutdown() {
   +     f.Logger.Flush()
   + }
90 
91   // Method to initialize the analytic module
92   func NewFileLogger(filename string) (analytics.Module, error) {
analytics/filesystem/file_module.go

@@ -200,6 +200,8 @@ func (p *PubstackModule) LogAmpObject(ao *analytics.AmpObject) {
p.eventChannels[amp].Push(payload)
}

func (p *PubstackModule) Shutdown() {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we closeAllEventChannels() or close(p.stopCh)?

202
203 - func (p *PubstackModule) Shutdown() {}
    + func (p *PubstackModule) Shutdown() {
    + }
    +    p.closeAllEventChannels()
    +    close(p.stopCh)
    + }
204  
205   func (p *PubstackModule) start(c <-chan *Configuration) {
analytics/pubstack/pubstack_module.go

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@guscarreon after inspection, i would say, leave it no-op, see the comments

@hhhjort
Copy link
Collaborator

hhhjort commented Mar 13, 2024

Just a friendly ping, are you still working on this?

@zhongshixi
Copy link
Contributor Author

zhongshixi commented Mar 21, 2024

@hhhjort yes, sorry for the late rely, i am slowing working on this, you can expect next week i will update the commit

@zhongshixi
Copy link
Contributor Author

going to resume the work today

@zhongshixi zhongshixi force-pushed the analytic-adapter-graceful-shutdown-interface branch from 1f0b6b0 to 4452580 Compare April 9, 2024 18:56
@AlexBVolcy
Copy link
Contributor

For future reference, can you not force push as it squashes the commits from the past making it harder to review. Thank you!

@zhongshixi
Copy link
Contributor Author

zhongshixi commented Apr 10, 2024

For future reference, can you not force push as it squashes the commits from the past making it harder to review. Thank you!

@AlexBVolcy thanks for pointing it out, the reason i force-push it is because the PR is based upon a very old version so i did git rebase - my intention is to have my very-old commit on the top of the latest commit head.

I will try to use merge back from master into development branch in the future

@@ -261,6 +261,11 @@ func (l *AgmaLogger) LogVideoObject(event *analytics.VideoObject) {
l.bufferCh <- data
}

func (l *AgmaLogger) Shutdown() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to add tests to cover these lines

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AlexBVolcy updated the unit test for it

@@ -85,6 +85,12 @@ func (f *FileLogger) LogNotificationEventObject(ne *analytics.NotificationEvent)
f.Logger.Flush()
}

// Shutdown the logger
func (f *FileLogger) Shutdown() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add test to cover these line?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AlexBVolcy updated unit test for it

@@ -85,6 +85,12 @@ func (f *FileLogger) LogNotificationEventObject(ne *analytics.NotificationEvent)
f.Logger.Flush()
}

// Shutdown the logger
func (f *FileLogger) Shutdown() {
// clear all pending buffered data in case there is any
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to follow the same pattern of the agma module, should we glog.Infof?

88   // Shutdown the logger
89   func (f *FileLogger) Shutdown() {
90       // clear all pending buffered data in case there is any
   +     glog.Infof("[FileLogger] Shutdown, trying to flush buffer")
91       f.Logger.Flush()
92   }
analytics/filesystem/file_module.go

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no additional args to template the log message, so glog.Info is sufficient.

@AlexBVolcy
Copy link
Contributor

@zhongshixi Hey! Just checking in on the status of this PR? I want to be clear that the code coverage comments that I left aren't critical to be implemented for approval as those Shutdown methods are tough to test. Just in case that's what's holding you up. Thank you!

@zhongshixi
Copy link
Contributor Author

@zhongshixi Hey! Just checking in on the status of this PR? I want to be clear that the code coverage comments that I left aren't critical to be implemented for approval as those Shutdown methods are tough to test. Just in case that's what's holding you up. Thank you!

@AlexBVolcy thanks for the update, i am trying to see if i can really do it without introducing too much hassles, i will give you an update on the PR before EOW.

i have urgent task to deal with this week for my company so sorry for the delay

@zhongshixi
Copy link
Contributor Author

still working on it

@zhongshixi
Copy link
Contributor Author

@AlexBVolcy have added some unit test according to your requests, let me know if they look good

@zhongshixi
Copy link
Contributor Author

cc @bsardo

Comment on lines 22 to 26
func (mw *MockLogger) Debug(v ...interface{}) {
mw.Called(v)
}

func (mw *MockLogger) Flush() {
Copy link
Contributor

@AlexBVolcy AlexBVolcy May 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Could you update the name of this variable to be ml?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

AlexBVolcy
AlexBVolcy previously approved these changes May 21, 2024
@guscarreon
Copy link
Contributor

Just like it was done in the AgmaLogger's implementation of Shutdown(), can we please add glog.Infof entries in the FileLogger and PubstackModule implementations?

88   // Shutdown the logger
89   func (f *FileLogger) Shutdown() {
90       // clear all pending buffered data in case there is any
   +     glog.Infof("[FileLogger] Shutdown, trying to flush buffer")
91       f.Logger.Flush()
92   }
analytics/filesystem/file_module.go

and

203   // Shutdown - no op since the analytic module already implements system signal handling
204   // and trying to close a closed channel will cause panic
205 - func (p *PubstackModule) Shutdown() {}
    + func (p *PubstackModule) Shutdown() {
    +     glog.Infof("[PubstackModule] Shutdown")
    + }
analytics/pubstack/pubstack_module.go

@zhongshixi
Copy link
Contributor Author

glog.Infof("[PubstackModule] Shutdown")

@guscarreon
i have updated the PR with your suggestion, take a look

AlexBVolcy
AlexBVolcy previously approved these changes May 23, 2024
@@ -93,6 +94,7 @@ func (f *FileLogger) LogNotificationEventObject(ne *analytics.NotificationEvent)
// Shutdown the logger
func (f *FileLogger) Shutdown() {
// clear all pending buffered data in case there is any
gglog.Info("[FileLogger] Shutdown, trying to flush buffer")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: can we reference this library as glog as it's done in other parts of the code?

@@ -5,6 +5,7 @@ import (
"fmt"

"github.com/chasex/glog"
gglog "github.com/golang/glog"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: can we reference this library as glog as it's done in other parts of the code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have two glogs here

the code uses two glogs and the existing implementation uses glog to refer github.com/chasex/glog

github.com/chasex/glog
github.com/golang/glog

if we use glog to refer to github.com/golang/glog , then we have to name "github.com/chasex/glog" to gglog or other proper name.

let me know your thought on it

Copy link
Contributor

@guscarreon guscarreon Jun 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like github.com/chasex/glog last commit was 8 years ago and we should probably move on to use github.com/golang/glog. If it gets complicated and it's too far out of the scope of this PR, I'm ready to approve. If we don't fix it, it'd be desirable to create an issue for later fix. Thank you for your updates @zhongshixi

Copy link
Contributor Author

@zhongshixi zhongshixi Jun 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i agree, i do not think it is actually complicated. let me change it so you can take a another look

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@guscarreon take another look, i aliased github.com/chasex/glog as clog so i do not change the critical implementation, the module now uses glog to output log information

Copy link
Contributor

@guscarreon guscarreon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@bsardo
Copy link
Collaborator

bsardo commented Jul 22, 2024

@zhongshixi sorry I'm coming in a bit late here. I was about to merge this but I noticed that we are introducing another logging library clog. Why do we need this when we already have glog? I suggest we only use one logging library.

@zhongshixi
Copy link
Contributor Author

@zhongshixi sorry I'm coming in a bit late here. I was about to merge this but I noticed that we are introducing another logging library clog. Why do we need this when we already have glog? I suggest we only use one logging library.

@bsardo i am not introducing a new log, i am simply renaming the existing library github.com/chasex/glog to clog so i can use glog to log the output which stays consistent across other modules.

you could refer to this comment chain for details
#3335 (comment)

@bsardo
Copy link
Collaborator

bsardo commented Jul 26, 2024

@zhongshixi sorry I'm coming in a bit late here. I was about to merge this but I noticed that we are introducing another logging library clog. Why do we need this when we already have glog? I suggest we only use one logging library.

@bsardo i am not introducing a new log, i am simply renaming the existing library github.com/chasex/glog to clog so i can use glog to log the output which stays consistent across other modules.

you could refer to this comment chain for details #3335 (comment)

Ah gotcha. Thanks for the clarification.

@bsardo bsardo merged commit ed3e4a1 into prebid:master Jul 29, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants