From 8a170e4afc91977a5468e2ded67a33fa9de2bf90 Mon Sep 17 00:00:00 2001 From: Chris Sinjakli <chris@gocardless.com> Date: Fri, 26 Jul 2019 13:33:43 +0100 Subject: [PATCH] Reopen files in DirectFileStore when the process has forked Currently, if you fork after altering a metric value when using DirectFileStore, the child process will have a handle to the original process's metric store. This commit detects checks for that condition on any instrumentation event and opens a new metric file for the new PID. Signed-off-by: Chris Sinjakli <chris@gocardless.com> --- .../client/data_stores/direct_file_store.rb | 7 ++++++- .../client/data_stores/direct_file_store_spec.rb | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/prometheus/client/data_stores/direct_file_store.rb b/lib/prometheus/client/data_stores/direct_file_store.rb index e9b0dcd3..9dbab76e 100644 --- a/lib/prometheus/client/data_stores/direct_file_store.rb +++ b/lib/prometheus/client/data_stores/direct_file_store.rb @@ -154,7 +154,12 @@ def store_key(labels) end def internal_store - @internal_store ||= FileMappedDict.new(filemap_filename) + if @store_opened_by_pid != process_id + @store_opened_by_pid = process_id + @internal_store = FileMappedDict.new(filemap_filename) + else + @internal_store + end end # Filename for this metric's PStore (one per process) diff --git a/spec/prometheus/client/data_stores/direct_file_store_spec.rb b/spec/prometheus/client/data_stores/direct_file_store_spec.rb index 52611adb..ba9d7d15 100644 --- a/spec/prometheus/client/data_stores/direct_file_store_spec.rb +++ b/spec/prometheus/client/data_stores/direct_file_store_spec.rb @@ -57,6 +57,18 @@ ms2.increment(labels: {}, by: 1) end + context "when process is forked" do + it "opens a new internal store to avoid two processes using the same file" do + allow(Process).to receive(:pid).and_return(12345) + metric_store = subject.for_metric(:metric_name, metric_type: :counter) + metric_store.increment(labels: {}, by: 1) + + allow(Process).to receive(:pid).and_return(23456) + metric_store.increment(labels: {}, by: 1) + expect(Dir.glob('/tmp/prometheus_test/*').size).to eq(2) + expect(metric_store.all_values).to eq({} => 2.0) + end + end context "for a non-gauge metric" do it "sums values from different processes by default" do