-
Notifications
You must be signed in to change notification settings - Fork 42
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
Scheduled post #848
base: master
Are you sure you want to change the base?
Scheduled post #848
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like some debug fmt.Println
statements are still left over from debugging. Let's clean them up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you so much for all your work on this, great job! I left some comments below, and I also agree with Agniva: we should remove all the fmt.Println
lines.
@agnivade @agarciamontoro can you please re-review this? I've made the fixes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will leave the store logic to Alejandro.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @harshilsharma63, and sorry for the delay in the review! Some more comments below.
ue.Store().DeleteScheduledPost(scheduledPostId) | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now DeleteScheduledPost doesn't return an error, but maybe it should (I left a comment for that). If we decide that's a good decision, then we need to return its error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think its of any use returning error from delete method, it doesn't matter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @harshilsharma63! I've left a comment in the RandomFutureTime
function, and I have an additional ask: I do think we should error out in MemStore
's DeleteScheduledPost
and UpdateScheduledPost
if the post is not found, and log an error if that's the case. It shouldn't happen and may point to other problems in the load-test.
Both Alejandro and Claudio are out. I will take another quick look and ask for a stamp approval. |
I gave it a test run and found some minor issues. We should be good to go after that. 1. Incorrect error/info logging when there are no scheduled posts. Log line is:
Note that the log level is error, but it's just a case of scheduled posts not being available. And we are correctly doing it here: scheduledPost, err := u.Store().GetRandomScheduledPost()
if err != nil {
return control.UserActionResponse{Err: control.NewUserError(err)}
}
if scheduledPost == nil {
return control.UserActionResponse{Info: "no scheduled posts found"}
} But the issue is that The right way is to return an error variable and check for it. See for example if len(teams) == 0 {
return model.Team{}, ErrTeamStoreEmpty
} and then we check for the error at call site: team, err := u.Store().RandomTeam(store.SelectMemberOf | store.SelectNotCurrent)
if errors.Is(err, memstore.ErrTeamStoreEmpty) {
return control.UserActionResponse{Info: "no other team to switch to"}
} else if err != nil {
return control.UserActionResponse{Err: control.NewUserError(err)}
} We should apply the same logic while calling 2. Invalid scheduled at time:
This is what I see in the server logs:
If we fix the above 2 issues, we should be good to go. |
Thanks for taking a look, @agnivade! |
I'll address the change next week and I'm getting the edit file functionality ready for feature complete by Monday |
Got it, @harshilsharma63, and thank you for your work here! |
@harshilsharma63 - Just checking to see the status on this. I think there are just a few minor things pending, and then we should be good to merge this. So hopefully not a lot of effort required. |
I'm working to finish scheduled posts on mobile before the feature complete date so have deferred this until that. Should be done in Feb first half. |
Thanks. Ideally, we should not be releasing features which are not load tested. @streamer45 - wondering if you can help bump up the priority on this so that Harshil is free to wrap up the work? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overhaul. Left mostly minor suggestions.
One additional comment is that I don't see any websocket addition here, and wondering how we are keeping the state in sync across multiple clients (e.g. deleting a draft).
loadtest/control/actions.go
Outdated
func ScheduledPostsEnabled(u user.User) (bool, UserActionResponse) { | ||
allow, err := strconv.ParseBool(u.Store().ClientConfig()["ScheduledPosts"]) | ||
if err != nil { | ||
fmt.Println("Error parsing ScheduledPosts config", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary log?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, removed.
post, err := u.Store().RandomPostForChannel(channel.Id) | ||
if err == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should handle the error case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
return control.UserActionResponse{Err: control.NewUserError(err)} | ||
} | ||
|
||
message, err := createMessage(u, channel, false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume we can schedule replies as well. A case to consider adding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, but this doesn't matter as all thats happening from isReply param is changing the avg word length, nothing else The part that send scheduled post as a reply is above where I set the rootId. But fixed this anyways as it is now semantically correct.
loadtest/utils_test.go
Outdated
} | ||
} | ||
|
||
func TestRandomFutureTimeZeroDuration(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I'd expect these to be subcases of TestRandomFutureTime
rather than top-level tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
loadtest/utils_test.go
Outdated
if randomTime < start.Unix() || randomTime > end.Unix() { | ||
t.Errorf("RandomFutureTime() = %v, want between %v and %v", randomTime, start.Unix(), end.Unix()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We may want to use the require
package for these checks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
// RandomFutureTime returns a random Unix timestamp, in milliseconds, in the interval | ||
// [now+deltaStart, now+deltaStart+maxUntil] | ||
func RandomFutureTime(deltaStart, maxUntil time.Duration) int64 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd find it more versatile if we returned a time.Time
and then let the caller format it as needed. Otherwise, if we can only foresee a timestamp usage, we could rename this to reflect its behavior better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's just one use case of this function right now and I don't want to spend excessive time refactoring this to accommodate all possible cases. This is fine for now can can be updated later as needed. I've already refactored this twice.
RootId: rootId, | ||
CreateAt: model.GetMillis(), | ||
}, | ||
ScheduledAt: loadtest.RandomFutureTime(time.Hour*24*2, time.Hour*24*10), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd really welcome named constants to make it straightforward to read, e.g. TwoDays
, TenDays
:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'd end up creating constants for every day. Skipping this for now.
return control.UserActionResponse{Info: "scheduled posts not enabled"} | ||
} | ||
|
||
scheduledPost, err := u.Store().GetRandomScheduledPost() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we ensuring GetRandomScheduledPost()
always returns non-deleted posts, if any?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While there is no explicit check for it, just like in other random functions, I am removing scheduled posts from store when deleting or posting them, so it will not return a deleted scheduled post.
@harshilsharma63 - Just wanted to check on this. Would you be able to find some time to address the review comments? |
@agnivade will do this tomorrow. Noted. |
@agnivade I've fixed the comments and invalid time error. |
Thanks! |
@harshilsharma63 Thoughts on my top comment above? On the websocket part. |
@agnivade @streamer45 I didn't know we had to do it. Can you share an example where this is being done and I'll refer it? Can you also explain a bit more about this? This is the first time I'm adding something to load test so I don't know the conventions and what all stuff needs to be done. I followed a channel bookmark example. |
Basically look at the simulcontroller/websocket.go file. We need to add event handlers for scheduled post events and keep the load-test agent state up to date. Although we don't do it for a lot of other events. But I agree that we should start doing it. |
Yeah, the idea is to mimic a real client's behavior as much as possible including any synchronization logic that may happen as a result of receiving a websocket event. Usually, I'd expect a Redux handler to be in place on the web implementation, which on this side can be converted to use the local store. See how we handle the posted event as a practical example: mattermost-load-test-ng/loadtest/user/userentity/websocket.go Lines 70 to 96 in 4954198
mattermost-load-test-ng/loadtest/control/simulcontroller/websocket.go Lines 32 to 62 in 4954198
You can notice we have two main places to handle ws events, based on what needs to happen. If we just need to save the data to the store, then we modify the internal |
@streamer45 - what are your thoughts on splitting the ws event handler to another PR? This PR has been up for 4 months and quite big already. I am thinking if we could merge this and send another PR after this for the ws handler. That way atleast we start getting some feature coverage for scheduled posts. |
Not opposed. Mostly I'd like to understand (from someone who developed the functionality) what ws events we need to handle and what the handling looks like. Do we make additional API requests in response? Is it just about saving data to the store? These questions help me understand what the performance impact of leaving these out could be.
I'd encourage us to understand more about that (I have a few thoughts, e.g. the choice of 3 reviewers). Maybe a quick retro would be beneficial since we want to make this process as seamless as possible. I'll remove myself from review to unblock and let @agarciamontoro do a final pass. Thanks for your patience :) |
just to keep state updated, thats the only purpose of WS handling.
The PR has been up for 4 months because I started working on another task and couldn't stop working on it to get back to this. |
To be clear, I wasn't explicitly looking for your review when I said the following 😛
I was hoping you could have a chat with the leads so that Harshil gets enough bandwidth to prioritise this load-test work. Otherwise, he was constantly getting pulled into developing other features. But you did a review, so no harm done 😄 @agarciamontoro - could you give this a final pass? Thanks. @harshilsharma63 - As Claudio outlined here: #848 (comment), we can set up event handlers for those ws events and update the store of the load-test agent to keep the state in sync. Let's schedule that work as a separate PR. |
Summary
Adding scheduled posts support to load test tool.
Ticket Link
Fixes https://mattermost.atlassian.net/browse/MM-61486