Skip to content

Commit

Permalink
Add Process memory usage and fix process state update (#1516)
Browse files Browse the repository at this point in the history
* fixes

* remove dep. Use Sidekiq approach

* move to PSS with a RSS fallback

* Fix lint warnings and reformat output

* Rescue exceptions

* fix linting

---------

Co-authored-by: Ben Sheldon [he/him] <[email protected]>
Co-authored-by: Ben Sheldon [he/him] <[email protected]>
  • Loading branch information
3 people authored Nov 21, 2024
1 parent c102011 commit 27c2a6d
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 5 deletions.
32 changes: 31 additions & 1 deletion app/models/good_job/process.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,28 @@ class Process < BaseRecord
STALE_INTERVAL = 30.seconds
# Interval until the process record is treated as expired
EXPIRED_INTERVAL = 5.minutes
PROCESS_MEMORY = case RUBY_PLATFORM
when /linux/
lambda do |pid|
File.readlines("/proc/#{pid}/smaps_rollup").each do |line|
next unless line.start_with?('Pss:')

break line.split[1].to_i
end
rescue Errno::ENOENT
File.readlines("/proc/#{pid}/status").each do |line|
next unless line.start_with?('VmRSS:')

break line.split[1].to_i
end
end
when /darwin|bsd/
lambda do |pid|
`ps -o pid,rss -p #{pid.to_i}`.lines.last.split.last.to_i
end
else
->(_pid) { 0 }
end

self.table_name = 'good_job_processes'
self.implicit_order_column = 'created_at'
Expand Down Expand Up @@ -56,6 +78,13 @@ def self.cleanup
end
end

# @return [Integer]
def self.memory_usage(pid)
PROCESS_MEMORY.call(pid)
rescue StandardError
0
end

def self.find_or_create_record(id:, with_advisory_lock: false)
attributes = {
id: id,
Expand Down Expand Up @@ -83,6 +112,7 @@ def self.process_state
{
hostname: Socket.gethostname,
pid: ::Process.pid,
memory: memory_usage(::Process.pid),
proctitle: $PROGRAM_NAME,
preserve_job_records: GoodJob.preserve_job_records,
retry_on_unhandled_error: GoodJob.retry_on_unhandled_error,
Expand All @@ -98,8 +128,8 @@ def self.process_state
end

def refresh
self.state = self.class.process_state
reload # verify the record still exists in the database
self.state = self.class.process_state
update(state: state, updated_at: Time.current)
rescue ActiveRecord::RecordNotFound
@new_record = true
Expand Down
1 change: 1 addition & 0 deletions app/views/good_job/processes/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<span class="badge rounded-pill bg-body-secondary text-secondary"><%= process.state["pid"] %></span>
<span class="text-muted small">@</span>
<span class="badge rounded-pill bg-body-secondary text-secondary"><%= process.state["hostname"] %></span>
<span class="badge rounded-pill bg-body-secondary text-secondary"><%= (process.state["memory"] / 1024).to_i %> MB</span>
</div>
</div>
<div class="col">
Expand Down
29 changes: 26 additions & 3 deletions config/brakeman.ignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"check_name": "SQL",
"message": "Possible SQL injection",
"file": "app/models/good_job/job.rb",
"line": 140,
"line": 135,
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
"code": "Arel.sql(\"(CASE #{queues.map.with_index do\n sanitize_sql_array([\"WHEN queue_name = ? THEN ?\", queue_name, index])\n end.join(\" \")} ELSE #{queues.size} END)\")",
"render_path": null,
Expand All @@ -68,8 +68,31 @@
89
],
"note": "Developer provided value, queue_name, is sanitized."
},
{
"warning_type": "Command Injection",
"warning_code": 14,
"fingerprint": "dbb80167f57edebfd9da72e1278d425095a0329755e24d3c50e0fda6bb21c097",
"check_name": "Execute",
"message": "Possible command injection",
"file": "app/models/good_job/process.rb",
"line": 32,
"link": "https://brakemanscanner.org/docs/warning_types/command_injection/",
"code": "`ps -o pid,rss -p #{pid.to_i}`",
"render_path": null,
"location": {
"type": "method",
"class": "Process",
"method": null
},
"user_input": "pid.to_i",
"confidence": "Medium",
"cwe_id": [
77
],
"note": ""
}
],
"updated": "2024-07-18 18:05:56 -0700",
"brakeman_version": "6.1.2"
"updated": "2024-11-16 17:00:20 -0600",
"brakeman_version": "6.2.1"
}
3 changes: 2 additions & 1 deletion spec/app/models/good_job/process_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@
process = described_class.create! state: {}, updated_at: 1.day.ago
expect do
expect(process.refresh).to be true
end.to change(process, :updated_at).to within(1.second).of(Time.current)
end.to change(process, :state)
.and change(process, :updated_at).to within(1.second).of(Time.current)
end

context 'when the record has been deleted elsewhere' do
Expand Down

0 comments on commit 27c2a6d

Please sign in to comment.