{"id":2272,"date":"2022-01-11T20:02:00","date_gmt":"2022-01-11T18:02:00","guid":{"rendered":"https:\/\/guven.atbakan.com\/blog\/?p=2272"},"modified":"2024-04-14T00:24:44","modified_gmt":"2024-04-13T21:24:44","slug":"writing-command-line-applications-tips-tricks-lock-the-command","status":"publish","type":"post","link":"https:\/\/guven.atbakan.com\/blog\/writing-command-line-applications-tips-tricks-lock-the-command\/","title":{"rendered":"Writing Command Line Applications \u2013 Tips &#038; Tricks \u2013 Lock the command"},"content":{"rendered":"<p>Locking the command is basically a double run prevention.<\/p>\n<p>Assume that you have a hourly email command and you&#8217;re sending e-mails to users one by one. If the command doesn&#8217;t finish until next hour, you may send multiple e-mails to some users. Or your colleague can try to start same command after you run it.<\/p>\n<pre><code class=\"language-php\">&lt;?php\n\/\/ RUN A:\n$users = User::where(&#039;hourly_email_sent&#039;, false)-&gt;get();\n\/\/ On above query, 10.000 users have been found. \n\/\/ The command started and already processed 8.000 users in one hour. There are 2.000 users remaining.\n\/\/ If you start command again, you&#039;ll send 2 emails for remaining 2.000 users. Because a command is already running and you started another one.\n\n\/\/ RUN B:\n$users = User::where(&#039;hourly_email_sent&#039;, false)-&gt;get();\n\/\/ On above query 2000+ users have been found.\n\/\/ RUN A and RUN B can contain same users!<\/code><\/pre>\n<p>I generally prefer to put a value to cache and check it before actually running the command. Here&#8217;s an example:<\/p>\n<pre><code class=\"language-php\">&lt;?php\n\n$cacheLockKey = &#039;command_name&#039;;\nif (Cache::has($cacheLockKey)) \n{\n    $this-&gt;output-&gt;writeln(&#039;Another process is already running. Exiting...&#039;);\n\n    return 1;\n}\n\nCache::put($cacheLockKey, date(&#039;Y-m-d H:i:s&#039;));\n\n\/\/ do some logic\n\nCache::forget($cacheLockKey);\n\nreturn 0;<\/code><\/pre>\n<p>This simple control will prevent you to run a command twice with mistake. It&#8217;s easy, isn&#8217;t it?<\/p>\n<h2>Downsides with putting lock into cache<\/h2>\n<p>You can use database or file storage too. I didn&#8217;t get trouble just because I&#8217;m using cache, but of course you can get problems somehow.<\/p>\n<p>If cache gets flushed for all values, your cache key will also be removed. You have to protect your lock until command is really finished.<\/p>\n<p>If you have multiple servers, you have to make sure all servers are using same cache storage.<\/p>\n<h2>Failure Case<\/h2>\n<p>If the command fails for a reason, you have to be sure cache key was removed. Otherwise command won&#8217;t start again.<\/p>\n<p>You can handle this situation manually, but if you&#8217;re running command on cronjob, your next run may not be able to succeed.<\/p>\n<p>This failure case of course depends whatever you want from a job.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Locking the command is basically a double run prevention. Assume that you have a hourly email command and you&#8217;re sending e-mails to users one by one. If the command doesn&#8217;t finish until next hour, you may send multiple e-mails to some users. Or your colleague can try to start same command after you run it. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[763],"tags":[767],"class_list":["post-2272","post","type-post","status-publish","format-standard","hentry","category-development-and-internet","tag-writing-command-line-applications-en"],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[],"version":6}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_likes_enabled":true,"jetpack-related-posts":[],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/posts\/2272","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/comments?post=2272"}],"version-history":[{"count":22,"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/posts\/2272\/revisions"}],"predecessor-version":[{"id":2392,"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/posts\/2272\/revisions\/2392"}],"wp:attachment":[{"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/media?parent=2272"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/categories?post=2272"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/guven.atbakan.com\/blog\/wp-json\/wp\/v2\/tags?post=2272"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}