From d1d3e0d0295415a9bde6499a18ad80a9b8a05bae Mon Sep 17 00:00:00 2001 From: Kyrylo Silin Date: Wed, 26 Feb 2020 18:49:43 +0800 Subject: [PATCH] stat: synchronize `to_h` with `increment_ms` Possibly fixes #545 (>4.4.0 <=4.13.0 causing RuntimeError: can't add a new key into hash during iteration) --- CHANGELOG.md | 2 ++ lib/airbrake-ruby/stat.rb | 25 +++++++++++++++---------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29d7bf3d..f68a16b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ Airbrake Ruby Changelog ([#562](https://github.com/airbrake/airbrake-ruby/pull/562)) * Fixed addition of duplicate filters on multiple `Airbrake.configure` calls ([#563](https://github.com/airbrake/airbrake-ruby/pull/563)) +* Improved thread-safety of `Airbrake::Stat` + ([#560](https://github.com/airbrake/airbrake-ruby/pull/560)) ### [v4.13.2][v4.13.2] (February 21, 2020) diff --git a/lib/airbrake-ruby/stat.rb b/lib/airbrake-ruby/stat.rb index 3fe414d3..1c800f37 100644 --- a/lib/airbrake-ruby/stat.rb +++ b/lib/airbrake-ruby/stat.rb @@ -24,18 +24,21 @@ def initialize(sum: 0.0, sumsq: 0.0, tdigest: TDigest.new(0.05)) @sum = sum @sumsq = sumsq @tdigest = tdigest + @mutex = Mutex.new end # @return [Hash{String=>Object}] stats as a hash with compressed TDigest # (serialized as base64) def to_h - tdigest.compress! - { - 'count' => tdigest.size, - 'sum' => sum, - 'sumsq' => sumsq, - 'tdigest' => Base64.strict_encode64(tdigest.as_small_bytes), - } + @mutex.synchronize do + tdigest.compress! + { + 'count' => tdigest.size, + 'sum' => sum, + 'sumsq' => sumsq, + 'tdigest' => Base64.strict_encode64(tdigest.as_small_bytes), + } + end end # Increments tdigest timings and updates tdigest with the difference between @@ -54,10 +57,12 @@ def increment(start_time, end_time = nil) # @param [Float] ms # @return [void] def increment_ms(ms) - self.sum += ms - self.sumsq += ms * ms + @mutex.synchronize do + self.sum += ms + self.sumsq += ms * ms - tdigest.push(ms) + tdigest.push(ms) + end end # We define custom inspect so that we weed out uninformative TDigest, which