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

OCPERT-9 Cache slack user/group IDs in runtime #357

Merged
merged 9 commits into from
Nov 22, 2024

Conversation

jhuttana
Copy link
Contributor

Could you please review the changes?

…the slack server

Signed-off-by: Jayashree Huttanagoudar <[email protected]>
@jhuttana
Copy link
Contributor Author

/cc @rioliu-rh

@jhuttana jhuttana marked this pull request as draft November 15, 2024 13:07
@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Nov 15, 2024
@@ -14,7 +14,7 @@


logger = logging.getLogger(__name__)

in_memory_cache = dict()
Copy link
Contributor

Choose a reason for hiding this comment

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

@jhuttana it's better to declare cache object as field of SlackClient, the class can be initialized in other module

@@ -265,11 +265,15 @@ def get_user_id_by_email(self, email):
str: slack user id
"""
email = self.transform_email(email)

if in_memory_cache.get(email) is not None:
return "<@%s>" % in_memory_cache.get(email)
Copy link
Contributor

Choose a reason for hiding this comment

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

@jhuttana this line has duplicate pattern declaration, suggest to declare local var userid, fill the var by if/else logic

userid = None
if email in cache_dict:
	userid = cache_dict.get(email)
else:
	// api call
  userid = resp["user"]["id"]
  cache_dict[email] = userid

return "<@%s>" % userid

it looks more efficient

Copy link
Contributor

Choose a reason for hiding this comment

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

also, we can add debug level log here to indicate the contact is retrieved from cache. so if you execute the cmd with option -v/--debug, the logic can be traced.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure

@@ -287,6 +291,8 @@ def get_group_id_by_name(self, name):
group id: slack group id
"""
ret_id = ""
if in_memory_cache.get(name) is not None:
Copy link
Contributor

Choose a reason for hiding this comment

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

@jhuttana same concern as above

@jhuttana
Copy link
Contributor Author

Thanks for the comments Rio. I will address these comments.

Signed-off-by: Jayashree Huttanagoudar <[email protected]>
@jhuttana jhuttana marked this pull request as ready for review November 18, 2024 08:50
@openshift-ci openshift-ci bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Nov 18, 2024
@@ -238,6 +237,8 @@ def send_email(self, to_addrs, subject, content):


class SlackClient:
cache_dict = dict()
Copy link
Contributor

@rioliu-rh rioliu-rh Nov 18, 2024

Choose a reason for hiding this comment

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

@jhuttana cache object should be moved to class constructor __init__ like self.cache = {}, all subsequent calls need to be changed as well. e.g. self.cache[xx]=y

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That would be perfect. I will do that.

…cache variable to the constructor

Signed-off-by: Jayashree Huttanagoudar <[email protected]>
@@ -239,6 +238,7 @@ def send_email(self, to_addrs, subject, content):

class SlackClient:
def __init__(self, bot_token):
self.cache_dict = dict()
Copy link
Contributor

@rioliu-rh rioliu-rh Nov 19, 2024

Choose a reason for hiding this comment

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

can we do code formatting, put all the local vars together

self.a = xx
self.b = yy

you can use formatter ms-python.black-formatter

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 will check that and try to apply

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For me it looks like declaring and initializing the runtime cache variable inside the constructor is fine (though it is referenced in two different methods). I don't see any difference in moving its declaration to the respective methods. For eg:

#Case-1: Declare and initialize the variable in constructor
class test:
    def __init__(self):
        self.attr1 = dict()
    
    def a(self):
        self.attr1 = {1:'one'}
        print(self.attr1) 
    
    def b(self):
        self.attr1 = {2:'two'}
        print(self.attr1)

#Case-2: Declare and initialize the variable in respective methods
class test1:
    def __init__(self):
        print("Inside test1 class")
    
    def aa(self):
        self.attr1 = dict()
        self.attr1 = {1:'one'}
        print(self.attr1) 
    
    def bb(self):
        self.attr1 = dict()
        self.attr1 = {2:'Two'}
        print(self.attr1) 
 
#For Case-1      
t = test()
t.a()  
t.b()

#For Case-2
tt = test1()
tt.aa()
tt.bb()

From your comment my understanding is that you are suggesting to go for Case-2 in the above example.
Though Case-1 and Case-2 are trying to achieve the same thing , Case-1 looks more efficient to me.
If my understanding is wrong could you please clarify what exactly are you suggesting?

Copy link
Contributor

Choose a reason for hiding this comment

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

I just want to make the code looks clean, put the all the local var declaration code together.

Suggested change
self.cache_dict = dict()
if not bot_token:
raise NotificationException("slack bot token is not available")
self.client = WebClient(token=bot_token)
self.cache_dict = dict()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ooops sorry !! I totally understood it in a different way :)
I will do that.


logger.debug(f"Cached email ids: {self.cache_dict}")
Copy link
Contributor

Choose a reason for hiding this comment

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

@jhuttana we should not output all the cached contacts at func level. it will cause trace log flood, my suggestion is add debug log entry for cache put/get ops. then the user can see which contact is cached and which one is retrieved from cache

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 think I am not getting it.
Do you mean to change it as: logger.debug(f"Cached email ids: {self.cache_dict.get(email)}") ?

Copy link
Contributor

Choose a reason for hiding this comment

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

if email in cache:
	// get userid from cache
  logger.debug(f"slack user id of {email} is retrieved from cached")
else:
  // get userid from api call
  // put the userid to cache object
  logger.debug(f"slack user id of {email} is cached")


if not ret_id:
raise NotificationException(
f"cannot find slack group id by name {name}")

logger.debug(f"Cached group ids: {self.cache_dict}")
Copy link
Contributor

Choose a reason for hiding this comment

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

…rom the cache or added to the cache

Signed-off-by: Jayashree Huttanagoudar <[email protected]>
@rioliu-rh
Copy link
Contributor

I think you need to create a new unit test to run funcs get_group_id_by_name/get_user_id_by_email multiple times to verify.
sample test case:

def test_get_slack_user_id(self):

enabled debug logging:
logging.basicConfig(
format="%(asctime)s: %(levelname)s: %(message)s",
datefmt="%Y-%m-%dT%H:%M:%SZ",
level=logging.DEBUG
)

@jhuttana
Copy link
Contributor Author

I think you need to create a new unit test to run funcs get_group_id_by_name/get_user_id_by_email multiple times to verify. sample test case:

def test_get_slack_user_id(self):

enabled debug logging:

logging.basicConfig(
format="%(asctime)s: %(levelname)s: %(message)s",
datefmt="%Y-%m-%dT%H:%M:%SZ",
level=logging.DEBUG
)

Sure I will give it a try

@rioliu-rh
Copy link
Contributor

/retest

2 similar comments
@rioliu-rh
Copy link
Contributor

/retest

@jhuttana
Copy link
Contributor Author

/retest

@rioliu-rh
Copy link
Contributor

you need to enable debug level logging in module test_notification.py, so you can see whether the user/group id can be retrieved from cache

@jhuttana
Copy link
Contributor Author

you need to enable debug level logging in module test_notification.py, so you can see whether the user/group id can be retrieved from cache

Sure will do that

@rioliu-rh
Copy link
Contributor

you need to enable debug level logging in module test_notification.py, so you can see whether the user/group id can be retrieved from cache

Sure will do that

if unit test is pass, we can merge this PR

Signed-off-by: Jayashree Huttanagoudar <[email protected]>
@jhuttana
Copy link
Contributor Author

Verify the unittest case

$ python -m unittest test_notification.TestNotificationManager.test_get_slack_user_id_from_cache
.
----------------------------------------------------------------------
Ran 1 test in 5.943s

OK

$ python -m unittest test_notification.TestNotificationManager.test_get_slack_group_id_from_cache
.
----------------------------------------------------------------------
Ran 1 test in 9.199s

OK

Signed-off-by: Jayashree Huttanagoudar <[email protected]>
Copy link

openshift-ci bot commented Nov 22, 2024

@jhuttana: all tests passed!

Full PR test history. Your PR dashboard.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@rioliu-rh
Copy link
Contributor

/lgtm
/approve

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Nov 22, 2024
Copy link

openshift-ci bot commented Nov 22, 2024

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: rioliu-rh

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Nov 22, 2024
@openshift-merge-bot openshift-merge-bot bot merged commit 6eeb77f into openshift:master Nov 22, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants