-
Notifications
You must be signed in to change notification settings - Fork 9.3k
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
[ISSUE-10650][BUGFIX] Prevent running again already running cron job #11465
Conversation
@diglin thanks for this pull request. The proposed change looks okay to me. Would you be able to take a look at adding a test that covers the code branch |
*/ | ||
protected function isJobRunning($jobCode) | ||
{ | ||
$runningJobs = $this->_getRunningSchedules(); |
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.
Would be great to replace this part to SQL query, that will be much effective than getting collection and iterate it.
* | ||
* @return bool | ||
*/ | ||
protected function isJobRunning($jobCode) |
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.
Would be great to use private instead of protected
@ihor-sviziev the other properties and methods of this class are in protected, I kept the same convention. If you want to change it, all other properties and methods need to be changed. It's outside of the scope of this issue. Same for the collection story, outside of the scope of the issue and the core team used the collection, even if I agree with you regarding the collection use. @fooman I worked few minutes to fix the issue and do manually testing with success. However few hours to try to set a unit test without success on saturday during the hackathon in Essen. I updated the other unit test to pass the test. I really gave a try to cover this case by mocking cron job schedule, class and so on but without success. I'm stuck to have one cron with status running and an other one with pending to run the test. When I use into the method |
@diglin unfortunately all other properties we can't change, it will not be backward compatible change. So it's can't be done in scope of this PR. |
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.
Would you consider making the requested changes. Might be a good thing to extract the new code into it's own class here also.
@@ -62,6 +62,11 @@ class ProcessCronQueueObserver implements ObserverInterface | |||
protected $_pendingSchedules; | |||
|
|||
/** | |||
* @var \Magento\Cron\Model\ResourceModel\Schedule\Collection | |||
*/ | |||
protected $_runningSchedules; |
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.
since this is new we can make this private and remove the _
from the name. All new properties should be private or public.
Remove `_` for properties for new properties / methods
@dmanners done |
Make property `private`
Make method `private`
@diglin @dmanners as I see you're checking that current job is already running. What do you think about using cron groups approach that was used in AOE Scheduler, maybe we need to add such groups functionality and prevent cron execution for group? |
Perhaps it would be better to implement this on Cron Group level, so that only single instance of given Group is running at once. If implemented in job level, the question is what is the purpose of Cron Groups then? In my mind Groups should be able to be used to define jobs that are related (eg. product import) and should not run concurrently, but can run concurrently with another Group (eg. order export). Secondly should we detect if the actual Group is running (via some IPC mechanism, or even by checking PID) and not depend on running status? If the process dies and running status is left behind, then it is never restarted. |
About cron job groups
I think this lock should be done in following way:
For all cases eache of these groups should be locked before cron execution and unlocked after execution. As result we will have backward compatible solution with preventing group running in parallel and ability to run cron job groups in parallel for people that really need it. Next improvement could be ability to manage cron job groups from the admin. About locks @dmanners @diglin @okobchenko what do you think? |
@ihor-sviziev I like the proposal. Going for the groups approach seems to make sense to me. |
@ihor-sviziev Looks nice, but I did not completely understand purpose of virtual group "all". If we introduce locking on cron group basis, I don't think we lose any backwards compatibility compared to current situation. Only thing I can think of is that someone has put multiple jobs into single group that should be ran parallel but now are not. That is not breaking any backwards compatibility per se. It will still work, not just parallel, and easily fixed by moving these to separate groups. In my opinion adding parameters to cron:run is going to wrong direction and introducing complexity on system level, which we should avoid. In my opinion the system should trigger single entry point, cron:run externally, and Magento should manage everything related to internal crons internally. EDIT: perhaps we should run all cron groups, including default group in a separate process, so that main entry point is not being blocked by anything? EDIT2: I like proposal of using MySQL based locking. We've used it earlier, and this works across multiple nodes. If we go for this + group based locking, then we can ideally have every node (not just primary node) running Magento cron, and tasks get picked by which ever node got there first. |
|
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.
@diglin could you update your code according to comments above?
Feel free to ask questions if you have any
I am closing this PR due to inactivity. Feel free to reach out to myself or @ihor-sviziev if you would like to pick up this pull request again later on. |
All comments provided are new feature which looks great by the way. But sorry, it's outside of the scope of this issue. At the end, you close the issue, do not merge it and NO ONE can benefit of the solution.... Well, why not open a new issue, provide your feedback there and create a new feature for that ! |
@diglin I see your point, but we couldn't merge just working solution when it was fixed not in optimal way. If we will merge this PR, it will be included to next release, but next PR could not be included. As result - next PR will not be backward compatible with these changes which is not really good, so it could not be fixed in good way till 2.3 release. Hope you understood my point. |
The solution provided by the other here raise an other issue: the whole cron group will be blocked if one cron job is running. If it last too long, the next run after the lock is released will won't necessary run the cron jobs because they are "missed" due to too late run. |
I finally found why I didn't receive notifications. My bad, my apologies. |
@diglin thank you for getting it. Probably we need to find solution for that. As a workaround when some cron job will take long time - you could extract it to separate group and this issue will go away. BTW if you found any issues in implementation that someone did - you could tell about it in that PR. |
Description
Create a logic to get running cron job and prevent them to be run again when pending job should be executed
Fixed Issues (if relevant)
Manual testing scenarios
Contribution checklist