{"id":12202,"date":"2023-11-27T06:59:26","date_gmt":"2023-11-27T14:59:26","guid":{"rendered":"https:\/\/www.coretechnologies.com\/blog\/?p=12202"},"modified":"2023-11-27T06:59:26","modified_gmt":"2023-11-27T14:59:26","slug":"python-script-single-instance","status":"publish","type":"post","link":"https:\/\/www.coretechnologies.com\/blog\/alwaysup\/python-script-single-instance\/","title":{"rendered":"Q&#038;A: How do I Enforce a Single Instance of my Python Script with AlwaysUp?"},"content":{"rendered":"<div align=\"center\"><img loading=\"lazy\" decoding=\"async\" class=\"no-lazy-load\" src=\"\/blog\/images\/qa-python-single-instance.webp\" style=\"margin-bottom:20px;\" title=\"How do I enforce a single instance of my Python app with AlwaysUp?\" alt=\"How do I enforce a single instance of my Python app with AlwaysUp?\" border=\"0\" width=\"380\" height=\"160\" \/><\/div>\n<div class=\"blog-qa-question-box\">\n<img loading=\"lazy\" decoding=\"async\" class=\"no-lazy-load\" src=\"https:\/\/cdn.coretechnologies.com\/images\/quotes-transparent-21x21.webp\" width=\"21\" height=\"21\" \/>&nbsp;&nbsp;Hi,<\/p>\n<p>I am trying the 30 day demo to see if AlwaysUp works for my application. I am running a couple of <a href=\"\/products\/AlwaysUp\/Apps\/RunPythonScriptAsAService.html\">python scripts<\/a> and so far your application works perfectly. I do however have an issue. It is critical that only one instance of my application runs when I run it from the command line my mutex works as it should.<\/p>\n<p>My code looks like this:<\/p>\n<div align=\"center\"><a href=\"\/blog\/images\/python-code-to-manage-mutex.png\" class=\"zoomPopup\" title=\"Python code to manage a mutex\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" class=\"image-padding\" src=\"\/blog\/images\/python-code-to-manage-mutex.png\" title=\"Python code to manage a mutex (click to enlarge)\" alt=\"Python code to manage a mutex\" border=\"0\" width=\"520\" \/><\/a><\/div>\n<p>I am able to run a second instance from a command line. This will cause some serious misreporting if two applications are running. Is there anything I can do?<\/p>\n<p>Thanks.<\/p>\n<p align=\"right\">&mdash; Carl<\/p>\n<\/div>\n<p>Hi Carl, thanks for trying AlwaysUp. Thanks also for sending your code, which enabled us to identify the problem quickly. It has to do with how <a href=\"https:\/\/en.wikipedia.org\/wiki\/Lock_(computer_science)\" target=\"_blank\" rel=\"noopener\">mutex locks<\/a> work.<\/p>\n<h2 class=\"blog-caption\">Your mutex isn&#8217;t visible across sessions<\/h2>\n<p>By default, mutexes have &#8220;session scope&#8221;. That is, they exist <b>only in the login session where they were created<\/b>. And that has important consequences.<\/p>\n<p>For example, let&#8217;s say that Alice logs in to a computer. Obviously, she can start a copy of your Python script just fine. But when Alice attempts to launch a second copy, it fails &mdash; exactly as you&#8217;ve designed.<\/p>\n<p>Now let&#8217;s say that Bill logs into his account on the same computer. Like Alice, he will be able to start only a single copy of your script.<\/p>\n<p>But there will now be <b>two instances of your Python script running<\/b> on the PC &mdash; one for Alice and one for Bill. That&#8217;s probably not what you want, right?<\/p>\n<p>In summary, your current single-instance enforcement mechanism will actually allow multiple copies because <b>your application creates a different mutex in each login session<\/b>.<\/p>\n<p>Now, let&#8217;s review why that&#8217;s important when running your Python script as a Windows Service.<\/p>\n<h2 class=\"blog-caption\">AlwaysUp runs your application in a different session<\/h2>\n<p>To start your Python script at boot, AlwaysUp runs it in the background in the <a href=\"\/WindowsServices\/FAQ.html#WhatIsSession0Isolation\">isolated Session 0<\/a>.<\/p>\n<p>And when you log into your computer, Windows creates a new session for you &mdash; Session 1, 2, or 3, etc.<\/p>\n<p>You&#8217;re able to &#8220;run a second instance from a command line&#8221; because the mutex doesn&#8217;t do its job across the two sessions.<\/p>\n<h2 class=\"blog-caption\">Use a Global mutex to restrict all instances of your app<\/h2>\n<p>Fortunately the fix is simple. Give our mutex a &#8220;global scope&#8221; so that it applies across all login sessions.<\/p>\n<p>Indeed, all you have to do is <b>prefix the name of your mutex with &#8220;Global\\&#8221;<\/b> (no quotes). It&#8217;s a one-line update to your code, like this:<\/p>\n<div class=\"code-box\">\nself.mutexname = app_name + &#8220;<b>Global\\<\/b>_mutex_{eaf8379e-5231-412c-92da-a0328eacea9e}&#8221;\n<\/div>\n<p>For additional context, check out Microsoft&#8217;s description of the situation in their <a href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/api\/system.threading.mutex\" target=\"_blank\" rel=\"noopener\">technical documentation on mutex objects<\/a>:<\/p>\n<div class=\"blog-qa-question-box\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/cdn.coretechnologies.com\/images\/quotes-transparent-21x21.png\" width=\"21\" height=\"21\" \/>&nbsp;On a server that is running Terminal Services, a named system mutex can have two levels of visibility. If its name begins with the prefix Global\\, the mutex is visible in all terminal server sessions. If its name begins with the prefix Local\\, the mutex is visible only in the terminal server session where it was created. In that case, a separate mutex with the same name can exist in each of the other terminal server sessions on the server. If you do not specify a prefix when you create a named mutex, it takes the prefix Local\\. Within a terminal server session, two mutexes whose names differ only by their prefixes are separate mutexes, and both are visible to all processes in the terminal server session. That is, the prefix names Global\\ and Local\\ describe the scope of the mutex name relative to terminal server sessions, not relative to processes.<\/p>\n<\/div>\n<p>Hopefully that all makes sense now.<\/p>\n<p style=\"margin-top: 30px\">\nPlease <a href=\"\/support\/\">get in touch<\/a> if you have any other questions running your Python scripts as Windows Services.\n<\/p>\n<div style=\"margin-top:30px\" align=\"center\">\n<div class=\"cta-button-1\">\n<table role=\"presentation\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" align=\"left\">\n<tbody>\n<tr>\n<td align=\"center\"><a href=\"\/blog\/tag\/alwaysup-tag\/\" title=\"More articles about AlwaysUp\"><span><nobr>More articles about AlwaysUp&#8230;<\/nobr><\/span><\/a><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<!-- relpost-thumb-wrapper --><div class=\"relpost-thumb-wrapper\"><!-- filter-class --><div class=\"relpost-thumb-container\"><style>.relpost-block-single-image, .relpost-post-image { margin-bottom: 10px; }<\/style><h3>You may also like...<\/h3><div style=\"clear: both\"><\/div><div style=\"clear: both\"><\/div><!-- relpost-block-container --><div class=\"relpost-block-container relpost-block-column-layout\" style=\"--relposth-columns: 3;--relposth-columns_t: 2; --relposth-columns_m: 2\"><a href=\"https:\/\/www.coretechnologies.com\/blog\/alwaysup\/login-credentials\/\"class=\"relpost-block-single\" ><div class=\"relpost-custom-block-single\"><img decoding=\"async\" loading=\"lazy\" class=\"relpost-block-single-image\" alt=\"Q&amp;A: Why Doesn&#039;t AlwaysUp Accept My Login Credentials?\"  src=\"https:\/\/www.coretechnologies.com\/blog\/wp-content\/uploads\/qa-trouble-entering-login-credentials-150x150-1.webp\" style=\"aspect-ratio:1\/1\" style=\"aspect-ratio:1\/1\"><\/img><div class=\"relpost-block-single-text\"  style=\"height: 75px;font-family: Arial;  font-size: 12px;  color: #333333;\"><h2 class=\"relpost_card_title\">Q&amp;A: Why Doesn&#039;t AlwaysUp Accept My Login Credentials?<\/h2><\/div><\/div><\/a><a href=\"https:\/\/www.coretechnologies.com\/blog\/windows-services\/windows-service-vs-web-service\/\"class=\"relpost-block-single\" ><div class=\"relpost-custom-block-single\"><img decoding=\"async\" loading=\"lazy\" class=\"relpost-block-single-image\" alt=\"Q&amp;A: What&#039;s the difference between a Windows Service and a Web Service?\"  src=\"https:\/\/www.coretechnologies.com\/blog\/wp-content\/uploads\/windows-service-vs-web-service-150x150-1.png\" style=\"aspect-ratio:1\/1\" style=\"aspect-ratio:1\/1\"><\/img><div class=\"relpost-block-single-text\"  style=\"height: 75px;font-family: Arial;  font-size: 12px;  color: #333333;\"><h2 class=\"relpost_card_title\">Q&amp;A: What&#039;s the difference between a Windows Service and a Web Service?<\/h2><\/div><\/div><\/a><a href=\"https:\/\/www.coretechnologies.com\/blog\/alwaysup\/trouble-reading-registry\/\"class=\"relpost-block-single\" ><div class=\"relpost-custom-block-single\"><img decoding=\"async\" loading=\"lazy\" class=\"relpost-block-single-image\" alt=\"Why does my Application have Trouble Reading the Registry?\"  src=\"https:\/\/www.coretechnologies.com\/blog\/wp-content\/uploads\/windows-registry-150-1501.png\" style=\"aspect-ratio:1\/1\" style=\"aspect-ratio:1\/1\"><\/img><div class=\"relpost-block-single-text\"  style=\"height: 75px;font-family: Arial;  font-size: 12px;  color: #333333;\"><h2 class=\"relpost_card_title\">Why does my Application have Trouble Reading the Registry?<\/h2><\/div><\/div><\/a><\/div><!-- close relpost-block-container --><div style=\"clear: both\"><\/div><\/div><!-- close filter class --><\/div><!-- close relpost-thumb-wrapper -->","protected":false},"excerpt":{"rendered":"<p>&nbsp;&nbsp;Hi, I am trying the 30 day demo to see if AlwaysUp works for my application. I am running a couple of python scripts and so far your application works perfectly. I do however have an issue. It is critical &hellip; <a href=\"https:\/\/www.coretechnologies.com\/blog\/alwaysup\/python-script-single-instance\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":12204,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[26,336,125,126,127,153],"class_list":["post-12202","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-alwaysup","tag-alwaysup-tag","tag-mutex-lock","tag-python","tag-python-script","tag-qa","tag-session-0-isolation"],"_links":{"self":[{"href":"https:\/\/www.coretechnologies.com\/blog\/wp-json\/wp\/v2\/posts\/12202","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.coretechnologies.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.coretechnologies.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.coretechnologies.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.coretechnologies.com\/blog\/wp-json\/wp\/v2\/comments?post=12202"}],"version-history":[{"count":10,"href":"https:\/\/www.coretechnologies.com\/blog\/wp-json\/wp\/v2\/posts\/12202\/revisions"}],"predecessor-version":[{"id":12253,"href":"https:\/\/www.coretechnologies.com\/blog\/wp-json\/wp\/v2\/posts\/12202\/revisions\/12253"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.coretechnologies.com\/blog\/wp-json\/wp\/v2\/media\/12204"}],"wp:attachment":[{"href":"https:\/\/www.coretechnologies.com\/blog\/wp-json\/wp\/v2\/media?parent=12202"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.coretechnologies.com\/blog\/wp-json\/wp\/v2\/categories?post=12202"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.coretechnologies.com\/blog\/wp-json\/wp\/v2\/tags?post=12202"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}