{"action":"created","comment":{"url":"https://api.github.com/repos/puppetlabs/pxp-agent/pulls/comments/45077759","id":45077759,"diff_hunk":"@@ -134,63 +143,102 @@ ActionOutcome Status::callAction(const ActionRequest& request) {\n     LOG_DEBUG(\"Retrieving results for job %1% from %2%\",\n               t_id, results_dir_path.string());\n \n-    auto metadata_file = (results_dir_path / \"metadata\").string();\n+    bool running_by_pid { false };\n+    bool not_running_by_pid { false };\n+    auto pid_file = (results_dir_path / \"pid\").string();\n+    std::string pid_txt {};\n+    int pid {};\n+\n+    // Read the PID file before the metadata, to avoid a race in the\n+    // non-blocking task thread, due to the elapsed time between the\n+    // end of the job and the metadata write\n+    if (!fs::exists(pid_file)) {\n+        LOG_DEBUG(\"PID file '%1%' does not exist\", pid_file);\n+    } else if (!lth_file::read(pid_file, pid_txt)) {\n+        LOG_ERROR(\"Failed to read PID file '%1%'\", pid_file);\n+    } else if (pid_txt.empty()) {\n+        LOG_ERROR(\"PID file '%1%' is empty\", pid_file);\n+    } else {\n+        try {\n+            pid = std::stoi(pid_txt);\n+            // NOTE(ale): processExists() does not throw\n+            if (Util::processExists(pid)) {\n+                // NOTE(ale): will set status to 'running' iff\n+                // metadata is valid and metadata.completed == false\n+                running_by_pid = true;\n+            } else {\n+                not_running_by_pid = true;\n+                bool cached { false };\n+                {\n+                    ResultsMutex::LockGuard a_l {\n+                        ResultsMutex::Instance().access_mtx };  // RAII\n+                    cached = ResultsMutex::Instance().exists(t_id);\n+                }\n+                if (cached) {\n+                    // The process doe not exist anymore, but its\n+                    // mutex is still cached - wait a bit before\n+                    // reading the metadata to allow the non-blocking\n+                    // to lock its mutex and update the metadata\n+                    pcp_util::this_thread::sleep_for(\n+                        pcp_util::chrono::milliseconds(METADATA_RACE_MS));\n+                }\n+            }\n+        } catch (const std::invalid_argument& e) {\n+            LOG_ERROR(\"Invalid value '%1%' stored in PID file '%2%'\",\n+                      pid_txt, pid_file);\n+        }\n+    }\n+\n     ActionMetadata metadata {};\n+    auto metadata_file = (results_dir_path / \"metadata\").string();\n \n     try {\n-        metadata = ActionMetadata(metadata_file);\n+        // Acquire the result mutex lock, if the transaction is cached\n+        ResultsMutex::Mutex_Ptr mtx_ptr;\n+        {\n+            ResultsMutex::LockGuard a_l {\n+                ResultsMutex::Instance().access_mtx };  // RAII\n+            if (ResultsMutex::Instance().exists(t_id)) {\n+                mtx_ptr = ResultsMutex::Instance().get(t_id);\n+            }\n+        }\n+        if (mtx_ptr != nullptr) {\n+            LOG_TRACE(\"Non-blocking transaction %1% mutex is cached; \"\n+                      \"locking it\", t_id);\n+            ResultsMutex::LockGuard r_l { *mtx_ptr };  // RAII\n+            metadata = ActionMetadata(metadata_file);\n+        } else {\n+            LOG_TRACE(\"Non-blocking transaction %1% mutex is not cached\", t_id);","path":"lib/src/modules/status.cc","position":110,"original_position":110,"commit_id":"39aa62763e747d7724810b47f320b3629fec2b00","original_commit_id":"39aa62763e747d7724810b47f320b3629fec2b00","user":{"login":"MikaelSmith","id":8162496,"avatar_url":"https://avatars.githubusercontent.com/u/8162496?v=3","gravatar_id":"","url":"https://api.github.com/users/MikaelSmith","html_url":"https://github.com/MikaelSmith","followers_url":"https://api.github.com/users/MikaelSmith/followers","following_url":"https://api.github.com/users/MikaelSmith/following{/other_user}","gists_url":"https://api.github.com/users/MikaelSmith/gists{/gist_id}","starred_url":"https://api.github.com/users/MikaelSmith/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/MikaelSmith/subscriptions","organizations_url":"https://api.github.com/users/MikaelSmith/orgs","repos_url":"https://api.github.com/users/MikaelSmith/repos","events_url":"https://api.github.com/users/MikaelSmith/events{/privacy}","received_events_url":"https://api.github.com/users/MikaelSmith/received_events","type":"User","site_admin":false},"body":"Is there a chance a new asynchronous task with the same pid could be started and claim the same mutex during this operation?","created_at":"2015-11-17T16:00:24Z","updated_at":"2015-11-17T16:00:24Z","html_url":"https://github.com/puppetlabs/pxp-agent/pull/246#discussion_r45077759","pull_request_url":"https://api.github.com/repos/puppetlabs/pxp-agent/pulls/246","_links":{"self":{"href":"https://api.github.com/repos/puppetlabs/pxp-agent/pulls/comments/45077759"},"html":{"href":"https://github.com/puppetlabs/pxp-agent/pull/246#discussion_r45077759"},"pull_request":{"href":"https://api.github.com/repos/puppetlabs/pxp-agent/pulls/246"}}},"pull_request":{"url":"https://api.github.com/repos/puppetlabs/pxp-agent/pulls/246","id":50749731,"html_url":"https://github.com/puppetlabs/pxp-agent/pull/246","diff_url":"https://github.com/puppetlabs/pxp-agent/pull/246.diff","patch_url":"https://github.com/puppetlabs/pxp-agent/pull/246.patch","issue_url":"https://api.github.com/repos/puppetlabs/pxp-agent/issues/246","number":246,"state":"open","locked":false,"title":"(PCP-172) Synchronize non-blocking tasks and status handlers","user":{"login":"parisiale","id":7150922,"avatar_url":"https://avatars.githubusercontent.com/u/7150922?v=3","gravatar_id":"","url":"https://api.github.com/users/parisiale","html_url":"https://github.com/parisiale","followers_url":"https://api.github.com/users/parisiale/followers","following_url":"https://api.github.com/users/parisiale/following{/other_user}","gists_url":"https://api.github.com/users/parisiale/gists{/gist_id}","starred_url":"https://api.github.com/users/parisiale/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/parisiale/subscriptions","organizations_url":"https://api.github.com/users/parisiale/orgs","repos_url":"https://api.github.com/users/parisiale/repos","events_url":"https://api.github.com/users/parisiale/events{/privacy}","received_events_url":"https://api.github.com/users/parisiale/received_events","type":"User","site_admin":false},"body":"With this commit we synchronize reading and writing operations on\r\ntransaction status metadata files by non-blocking tasks and status\r\nrequests handlers.\r\n\r\nThe status query action now reads the PID file before accessing the\r\nmetadata file. In case the PID is related to a non-existent process, and\r\nits mutex is still in the cache, the status handler will sleep for 0.1 s,\r\nto ensure that the non-blocking task has the time to lock the mutex\r\nand update the metadata file.\r\n\r\nThe synchronization relies on the ResultsMutex singleton that caches\r\nmutexes named against transaction IDs.","created_at":"2015-11-15T16:15:22Z","updated_at":"2015-11-17T16:00:24Z","closed_at":null,"merged_at":null,"merge_commit_sha":"faec268bf4a06bdd19ff8e19878e096d43b54c8c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/puppetlabs/pxp-agent/pulls/246/commits","review_comments_url":"https://api.github.com/repos/puppetlabs/pxp-agent/pulls/246/comments","review_comment_url":"https://api.github.com/repos/puppetlabs/pxp-agent/pulls/comments{/number}","comments_url":"https://api.github.com/repos/puppetlabs/pxp-agent/issues/246/comments","statuses_url":"https://api.github.com/repos/puppetlabs/pxp-agent/statuses/39aa62763e747d7724810b47f320b3629fec2b00","head":{"label":"parisiale:PCP-172","ref":"PCP-172","sha":"39aa62763e747d7724810b47f320b3629fec2b00","user":{"login":"parisiale","id":7150922,"avatar_url":"https://avatars.githubusercontent.com/u/7150922?v=3","gravatar_id":"","url":"https://api.github.com/users/parisiale","html_url":"https://github.com/parisiale","followers_url":"https://api.github.com/users/parisiale/followers","following_url":"https://api.github.com/users/parisiale/following{/other_user}","gists_url":"https://api.github.com/users/parisiale/gists{/gist_id}","starred_url":"https://api.github.com/users/parisiale/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/parisiale/subscriptions","organizations_url":"https://api.github.com/users/parisiale/orgs","repos_url":"https://api.github.com/users/parisiale/repos","events_url":"https://api.github.com/users/parisiale/events{/privacy}","received_events_url":"https://api.github.com/users/parisiale/received_events","type":"User","site_admin":false},"repo":{"id":43742732,"name":"pxp-agent","full_name":"parisiale/pxp-agent","owner":{"login":"parisiale","id":7150922,"avatar_url":"https://avatars.githubusercontent.com/u/7150922?v=3","gravatar_id":"","url":"https://api.github.com/users/parisiale","html_url":"https://github.com/parisiale","followers_url":"https://api.github.com/users/parisiale/followers","following_url":"https://api.github.com/users/parisiale/following{/other_user}","gists_url":"https://api.github.com/users/parisiale/gists{/gist_id}","starred_url":"https://api.github.com/users/parisiale/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/parisiale/subscriptions","organizations_url":"https://api.github.com/users/parisiale/orgs","repos_url":"https://api.github.com/users/parisiale/repos","events_url":"https://api.github.com/users/parisiale/events{/privacy}","received_events_url":"https://api.github.com/users/parisiale/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/parisiale/pxp-agent","description":"Puppet eXecution Protocol Agent","fork":true,"url":"https://api.github.com/repos/parisiale/pxp-agent","forks_url":"https://api.github.com/repos/parisiale/pxp-agent/forks","keys_url":"https://api.github.com/repos/parisiale/pxp-agent/keys{/key_id}","collaborators_url":"https://api.github.com/repos/parisiale/pxp-agent/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/parisiale/pxp-agent/teams","hooks_url":"https://api.github.com/repos/parisiale/pxp-agent/hooks","issue_events_url":"https://api.github.com/repos/parisiale/pxp-agent/issues/events{/number}","events_url":"https://api.github.com/repos/parisiale/pxp-agent/events","assignees_url":"https://api.github.com/repos/parisiale/pxp-agent/assignees{/user}","branches_url":"https://api.github.com/repos/parisiale/pxp-agent/branches{/branch}","tags_url":"https://api.github.com/repos/parisiale/pxp-agent/tags","blobs_url":"https://api.github.com/repos/parisiale/pxp-agent/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/parisiale/pxp-agent/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/parisiale/pxp-agent/git/refs{/sha}","trees_url":"https://api.github.com/repos/parisiale/pxp-agent/git/trees{/sha}","statuses_url":"https://api.github.com/repos/parisiale/pxp-agent/statuses/{sha}","languages_url":"https://api.github.com/repos/parisiale/pxp-agent/languages","stargazers_url":"https://api.github.com/repos/parisiale/pxp-agent/stargazers","contributors_url":"https://api.github.com/repos/parisiale/pxp-agent/contributors","subscribers_url":"https://api.github.com/repos/parisiale/pxp-agent/subscribers","subscription_url":"https://api.github.com/repos/parisiale/pxp-agent/subscription","commits_url":"https://api.github.com/repos/parisiale/pxp-agent/commits{/sha}","git_commits_url":"https://api.github.com/repos/parisiale/pxp-agent/git/commits{/sha}","comments_url":"https://api.github.com/repos/parisiale/pxp-agent/comments{/number}","issue_comment_url":"https://api.github.com/repos/parisiale/pxp-agent/issues/comments{/number}","contents_url":"https://api.github.com/repos/parisiale/pxp-agent/contents/{+path}","compare_url":"https://api.github.com/repos/parisiale/pxp-agent/compare/{base}...{head}","merges_url":"https://api.github.com/repos/parisiale/pxp-agent/merges","archive_url":"https://api.github.com/repos/parisiale/pxp-agent/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/parisiale/pxp-agent/downloads","issues_url":"https://api.github.com/repos/parisiale/pxp-agent/issues{/number}","pulls_url":"https://api.github.com/repos/parisiale/pxp-agent/pulls{/number}","milestones_url":"https://api.github.com/repos/parisiale/pxp-agent/milestones{/number}","notifications_url":"https://api.github.com/repos/parisiale/pxp-agent/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/parisiale/pxp-agent/labels{/name}","releases_url":"https://api.github.com/repos/parisiale/pxp-agent/releases{/id}","created_at":"2015-10-06T09:59:49Z","updated_at":"2015-10-06T09:59:50Z","pushed_at":"2015-11-16T12:24:18Z","git_url":"git://github.com/parisiale/pxp-agent.git","ssh_url":"git@github.com:parisiale/pxp-agent.git","clone_url":"https://github.com/parisiale/pxp-agent.git","svn_url":"https://github.com/parisiale/pxp-agent","homepage":"","size":8958,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"puppetlabs:master","ref":"master","sha":"9c82e66bce6358051f9684ec2e12a20f0339f832","user":{"login":"puppetlabs","id":234268,"avatar_url":"https://avatars.githubusercontent.com/u/234268?v=3","gravatar_id":"","url":"https://api.github.com/users/puppetlabs","html_url":"https://github.com/puppetlabs","followers_url":"https://api.github.com/users/puppetlabs/followers","following_url":"https://api.github.com/users/puppetlabs/following{/other_user}","gists_url":"https://api.github.com/users/puppetlabs/gists{/gist_id}","starred_url":"https://api.github.com/users/puppetlabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/puppetlabs/subscriptions","organizations_url":"https://api.github.com/users/puppetlabs/orgs","repos_url":"https://api.github.com/users/puppetlabs/repos","events_url":"https://api.github.com/users/puppetlabs/events{/privacy}","received_events_url":"https://api.github.com/users/puppetlabs/received_events","type":"Organization","site_admin":false},"repo":{"id":23231786,"name":"pxp-agent","full_name":"puppetlabs/pxp-agent","owner":{"login":"puppetlabs","id":234268,"avatar_url":"https://avatars.githubusercontent.com/u/234268?v=3","gravatar_id":"","url":"https://api.github.com/users/puppetlabs","html_url":"https://github.com/puppetlabs","followers_url":"https://api.github.com/users/puppetlabs/followers","following_url":"https://api.github.com/users/puppetlabs/following{/other_user}","gists_url":"https://api.github.com/users/puppetlabs/gists{/gist_id}","starred_url":"https://api.github.com/users/puppetlabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/puppetlabs/subscriptions","organizations_url":"https://api.github.com/users/puppetlabs/orgs","repos_url":"https://api.github.com/users/puppetlabs/repos","events_url":"https://api.github.com/users/puppetlabs/events{/privacy}","received_events_url":"https://api.github.com/users/puppetlabs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/puppetlabs/pxp-agent","description":"PCP eXecution Protocol Agent","fork":false,"url":"https://api.github.com/repos/puppetlabs/pxp-agent","forks_url":"https://api.github.com/repos/puppetlabs/pxp-agent/forks","keys_url":"https://api.github.com/repos/puppetlabs/pxp-agent/keys{/key_id}","collaborators_url":"https://api.github.com/repos/puppetlabs/pxp-agent/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/puppetlabs/pxp-agent/teams","hooks_url":"https://api.github.com/repos/puppetlabs/pxp-agent/hooks","issue_events_url":"https://api.github.com/repos/puppetlabs/pxp-agent/issues/events{/number}","events_url":"https://api.github.com/repos/puppetlabs/pxp-agent/events","assignees_url":"https://api.github.com/repos/puppetlabs/pxp-agent/assignees{/user}","branches_url":"https://api.github.com/repos/puppetlabs/pxp-agent/branches{/branch}","tags_url":"https://api.github.com/repos/puppetlabs/pxp-agent/tags","blobs_url":"https://api.github.com/repos/puppetlabs/pxp-agent/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/puppetlabs/pxp-agent/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/puppetlabs/pxp-agent/git/refs{/sha}","trees_url":"https://api.github.com/repos/puppetlabs/pxp-agent/git/trees{/sha}","statuses_url":"https://api.github.com/repos/puppetlabs/pxp-agent/statuses/{sha}","languages_url":"https://api.github.com/repos/puppetlabs/pxp-agent/languages","stargazers_url":"https://api.github.com/repos/puppetlabs/pxp-agent/stargazers","contributors_url":"https://api.github.com/repos/puppetlabs/pxp-agent/contributors","subscribers_url":"https://api.github.com/repos/puppetlabs/pxp-agent/subscribers","subscription_url":"https://api.github.com/repos/puppetlabs/pxp-agent/subscription","commits_url":"https://api.github.com/repos/puppetlabs/pxp-agent/commits{/sha}","git_commits_url":"https://api.github.com/repos/puppetlabs/pxp-agent/git/commits{/sha}","comments_url":"https://api.github.com/repos/puppetlabs/pxp-agent/comments{/number}","issue_comment_url":"https://api.github.com/repos/puppetlabs/pxp-agent/issues/comments{/number}","contents_url":"https://api.github.com/repos/puppetlabs/pxp-agent/contents/{+path}","compare_url":"https://api.github.com/repos/puppetlabs/pxp-agent/compare/{base}...{head}","merges_url":"https://api.github.com/repos/puppetlabs/pxp-agent/merges","archive_url":"https://api.github.com/repos/puppetlabs/pxp-agent/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/puppetlabs/pxp-agent/downloads","issues_url":"https://api.github.com/repos/puppetlabs/pxp-agent/issues{/number}","pulls_url":"https://api.github.com/repos/puppetlabs/pxp-agent/pulls{/number}","milestones_url":"https://api.github.com/repos/puppetlabs/pxp-agent/milestones{/number}","notifications_url":"https://api.github.com/repos/puppetlabs/pxp-agent/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/puppetlabs/pxp-agent/labels{/name}","releases_url":"https://api.github.com/repos/puppetlabs/pxp-agent/releases{/id}","created_at":"2014-08-22T16:25:01Z","updated_at":"2015-10-19T23:27:50Z","pushed_at":"2015-11-17T12:54:33Z","git_url":"git://github.com/puppetlabs/pxp-agent.git","ssh_url":"git@github.com:puppetlabs/pxp-agent.git","clone_url":"https://github.com/puppetlabs/pxp-agent.git","svn_url":"https://github.com/puppetlabs/pxp-agent","homepage":"","size":8846,"stargazers_count":2,"watchers_count":2,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":13,"mirror_url":null,"open_issues_count":4,"forks":13,"open_issues":4,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/puppetlabs/pxp-agent/pulls/246"},"html":{"href":"https://github.com/puppetlabs/pxp-agent/pull/246"},"issue":{"href":"https://api.github.com/repos/puppetlabs/pxp-agent/issues/246"},"comments":{"href":"https://api.github.com/repos/puppetlabs/pxp-agent/issues/246/comments"},"review_comments":{"href":"https://api.github.com/repos/puppetlabs/pxp-agent/pulls/246/comments"},"review_comment":{"href":"https://api.github.com/repos/puppetlabs/pxp-agent/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/puppetlabs/pxp-agent/pulls/246/commits"},"statuses":{"href":"https://api.github.com/repos/puppetlabs/pxp-agent/statuses/39aa62763e747d7724810b47f320b3629fec2b00"}}}}