catpm 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2a84d81e5f4bbf2dca6af9f3b1c91d18af2160e9a15e24c8093216be4b8c5e20
4
- data.tar.gz: 347b9026049cb39becf4d7618996c3091ddc0243115efdf47e689c644ec03f89
3
+ metadata.gz: 722853b2fcfcd675b06e698948f58e7b169041f966371e7699ced35b1ae83b8f
4
+ data.tar.gz: 867594a5c8631535eafb45cfdd66626c4403dea1d550e29c6b7103e7c9893500
5
5
  SHA512:
6
- metadata.gz: da7474f427ad062a4cad9098263adacc90df2835cc8e2425689363346e805ca3fa520870fe2366cb750ea0f47bb3579adc06872891c413a2bcb9bd9222467278
7
- data.tar.gz: a1161b1475b8c45654a6e0833cc1884686adaf2bdb1de5293c8337085e5e290503399053a19d2c3d2ce1fce2c79cc7ec0b31ea5d0e31207ffaff3a32ce50710b
6
+ metadata.gz: c686066f30115d154c8d05e0a9a47d69c09a4221e02a2c46550c144426914da2aa34f2e6df7bd601326f7e43b009823a9956224afa10aa28536eb0f5e1495021
7
+ data.tar.gz: 29581810d90caf496eb63f8e28493bbed6783919f48c134cada3fc7141540a74dc4bb84c8d933b28a0f44d5d6a7510fa514a686163794bc66b056c548e64a879
data/README.md CHANGED
@@ -1,3 +1,6 @@
1
+ gem build catpm.gemspec
2
+ gem push catpm-0.1.2.gem
3
+
1
4
  # Catpm
2
5
 
3
6
  Lightweight, self-hosted performance monitoring for Rails. Track requests, background jobs, errors, and custom traces — all stored in your existing database. No external services, no Redis, no extra infrastructure.
data/lib/catpm/flusher.rb CHANGED
@@ -12,28 +12,54 @@ module Catpm
12
12
  @last_cleanup_at = Time.now
13
13
  @running = false
14
14
  @thread = nil
15
+ @pid = nil
16
+ @mutex = Mutex.new
15
17
  end
16
18
 
17
19
  def start
18
- return if @running
20
+ @mutex.synchronize do
21
+ # After fork(), threads are dead but @running may still be true
22
+ if @pid && @pid != Process.pid
23
+ @running = false
24
+ @thread = nil
25
+ end
26
+
27
+ return if @running
19
28
 
20
- @running = true
21
- @thread = Thread.new do
22
- while @running
23
- sleep(effective_interval)
24
- flush_cycle if @running
29
+ @running = true
30
+ @pid = Process.pid
31
+ @thread = Thread.new do
32
+ while @running
33
+ sleep(effective_interval)
34
+ flush_cycle if @running
35
+ end
36
+ rescue => e
37
+ Catpm.config.error_handler.call(e)
38
+ retry if @running
25
39
  end
26
- rescue => e
27
- Catpm.config.error_handler.call(e)
28
- retry if @running
29
40
  end
30
41
  end
31
42
 
43
+ # Cheap check called from middleware on every request.
44
+ # Detects fork (Puma, Unicorn, etc.) and restarts the thread.
45
+ def ensure_running!
46
+ return if @running && @thread&.alive? && @pid == Process.pid
47
+
48
+ start
49
+ end
50
+
32
51
  def stop(timeout: Catpm.config.shutdown_timeout)
33
- return unless @running
52
+ thread = nil
34
53
 
35
- @running = false
36
- @thread&.join(timeout)
54
+ @mutex.synchronize do
55
+ return unless @running
56
+
57
+ @running = false
58
+ thread = @thread
59
+ @thread = nil
60
+ end
61
+
62
+ thread&.join(timeout)
37
63
  flush_cycle # Final flush
38
64
  end
39
65
 
@@ -44,29 +70,29 @@ module Catpm
44
70
  events = @buffer.drain
45
71
  return if events.empty?
46
72
 
47
- perf_events, custom_events = events.partition { |e| e.is_a?(Catpm::Event) }
73
+ ActiveRecord::Base.connection_pool.with_connection do
74
+ ActiveRecord::Base.transaction do
75
+ perf_events, custom_events = events.partition { |e| e.is_a?(Catpm::Event) }
48
76
 
49
- if perf_events.any?
50
- buckets, samples, errors = aggregate(perf_events)
77
+ if perf_events.any?
78
+ buckets, samples, errors = aggregate(perf_events)
51
79
 
52
- ActiveRecord::Base.connection_pool.with_connection do
53
- adapter = Catpm::Adapter.current
54
- adapter.persist_buckets(buckets)
80
+ adapter = Catpm::Adapter.current
81
+ adapter.persist_buckets(buckets)
55
82
 
56
- bucket_map = build_bucket_map(buckets)
57
- samples = rotate_samples(samples)
58
- adapter.persist_samples(samples, bucket_map)
59
- adapter.persist_errors(errors)
60
- end
61
- end
83
+ bucket_map = build_bucket_map(buckets)
84
+ samples = rotate_samples(samples)
85
+ adapter.persist_samples(samples, bucket_map)
86
+ adapter.persist_errors(errors)
87
+ end
62
88
 
63
- if custom_events.any?
64
- event_buckets, event_samples = aggregate_custom_events(custom_events)
89
+ if custom_events.any?
90
+ event_buckets, event_samples = aggregate_custom_events(custom_events)
65
91
 
66
- ActiveRecord::Base.connection_pool.with_connection do
67
- adapter = Catpm::Adapter.current
68
- adapter.persist_event_buckets(event_buckets)
69
- adapter.persist_event_samples(event_samples)
92
+ adapter = Catpm::Adapter.current
93
+ adapter.persist_event_buckets(event_buckets)
94
+ adapter.persist_event_samples(event_samples)
95
+ end
70
96
  end
71
97
  end
72
98
 
@@ -75,8 +101,10 @@ module Catpm
75
101
 
76
102
  maybe_cleanup
77
103
  rescue => e
104
+ events&.each { |ev| @buffer.push(ev) }
78
105
  @circuit.record_failure
79
106
  Catpm.config.error_handler.call(e)
107
+ Rails.logger.error("[catpm] flush error: #{e.class}: #{e.message}\n#{e.backtrace&.first(5)&.join("\n")}")
80
108
  end
81
109
 
82
110
  def reset!
@@ -10,17 +10,11 @@ module Catpm
10
10
  initialize_flusher
11
11
  apply_patches
12
12
 
13
- # Always start the flusher in the current process.
14
- # For forking servers, also register post-fork hooks
15
- # so each worker restarts its own flusher.
13
+ # Start the flusher in the current process.
14
+ # For forking servers (Puma, Passenger, Unicorn, etc.),
15
+ # the middleware detects fork via PID and restarts automatically.
16
16
  Catpm.flusher&.start
17
17
 
18
- if defined?(::PhusionPassenger)
19
- register_passenger_hook
20
- elsif defined?(::Pitchfork)
21
- register_pitchfork_hook
22
- end
23
-
24
18
  register_shutdown_hooks
25
19
  end
26
20
 
@@ -57,20 +51,6 @@ module Catpm
57
51
  jitter: Catpm.config.flush_jitter
58
52
  )
59
53
  end
60
-
61
- def register_passenger_hook
62
- flusher = Catpm.flusher
63
- ::PhusionPassenger.on_event(:starting_worker_process) do |forked|
64
- flusher&.start if forked
65
- end
66
- end
67
-
68
- def register_pitchfork_hook
69
- flusher = Catpm.flusher
70
- ::Pitchfork.configure do |server|
71
- server.after_worker_fork { flusher&.start }
72
- end
73
- end
74
54
  end
75
55
  end
76
56
  end
@@ -9,6 +9,8 @@ module Catpm
9
9
  def call(env)
10
10
  return @app.call(env) unless Catpm.enabled?
11
11
 
12
+ Catpm.flusher&.ensure_running!
13
+
12
14
  env['catpm.request_start'] = Process.clock_gettime(Process::CLOCK_MONOTONIC)
13
15
 
14
16
  if Catpm.config.instrument_segments
data/lib/catpm/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Catpm
4
- VERSION = '0.1.2'
4
+ VERSION = '0.1.4'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: catpm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - ''