Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optimizations and setting to retry failed Plex requests #13

Merged
merged 7 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ jobs:

echo 'EOF' >> $GITHUB_ENV

# Only build and push Docker images for releases
- name: Build and push Docker image to GitHub Container Registry
uses: docker/build-push-action@v2
if: ${{ github.event_name == 'release' }}
with:
context: .
push: true
Expand All @@ -65,6 +67,7 @@ jobs:
cache-to: type=local,dest=/tmp/.buildx-cache-new

- name: Update Docker buildx cache
if: ${{ github.event_name == 'release' }}
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ These environment variables can be passed into the container (defaults are in pa
- Plex Media Server token
* `PLEX_TIMEOUT` (`10`)
- How long to wait for Plex Media Server to respond
* `PLEX_RETRIES_COUNT` (`0`)
- How many times to retry failed Plex Media Server requests
* `METRICS_PREFIX` (`plex`)
- What to prefix metric names with
* `METRICS_MEDIA_COLLECTING_INTERVAL_SECONDS` (`300`)
Expand Down
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ services:
# Can be set in .env
- PLEX_ADDR=${PLEX_ADDR}
- PLEX_TOKEN=${PLEX_TOKEN}
- PLEX_TIMEOUT=${PLEX_TIMEOUT}
- PLEX_RETRIES_COUNT=${PLEX_RETRIES_COUNT}
- METRICS_MEDIA_COLLECTING_INTERVAL_SECONDS=300
volumes:
- .:/srv:delegated
Expand Down
66 changes: 52 additions & 14 deletions lib/middleware/collector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ def initialize(app)

# Plex configs
@plex_addr = ENV["PLEX_ADDR"] || "http://localhost:32400"
@plex_token = ENV["PLEX_TOKEN"]
@plex_timeout = ENV["PLEX_TIMEOUT"]&.to_i || 10
@plex_retries_count = ENV["PLEX_RETRIES_COUNT"]&.to_i || 0

# Metrics configs
@metrics_prefix = ENV["METRICS_PREFIX"] || "plex"
Expand Down Expand Up @@ -54,21 +56,32 @@ def initialize(app)
end

def call(env)
case env["PATH_INFO"]
when "/metrics"
collect_metrics
end

@app.call(env)
end

def collect_metrics
log(step: "collect_metrics")

begin
capabilities_resource = send_plex_api_request(method: :get, endpoint: "/").dig("MediaContainer")
capabilities_resource = send_plex_api_request(method: :get, endpoint: "/identity").dig("MediaContainer")
metric_up_value = 1

log(plex_up: true)

set_gauge_metric_values_or_reset_missing(
metric: @metrics[:info],
values: {
{ version: capabilities_resource.dig("version") } => 1,
},
)

collect_session_metrics
collect_activity_metrics
collect_media_metrics
rescue HTTP::Error
log(plex_up: false)

# Value of 0 means there's no heartbeat
metric_up_value = 0
ensure
Expand All @@ -80,11 +93,23 @@ def call(env)
)
end

@app.call(env)
[
-> { collect_session_metrics },
-> { collect_activity_metrics },
-> { collect_media_metrics },
].each do |collection|
collection.call
rescue HTTP::Error
# Skip if it errors out
end
end

private

def log(**labels)
puts(labels.to_a.map { |k, v| "#{k}=#{v}" }.join(" "))
end

def collect_activity_metrics
values = Hash.new { |h, k| h[k] = 0 }

Expand Down Expand Up @@ -203,15 +228,28 @@ def fetch_media_section_count(key:, params: {}, **options)
end

def send_plex_api_request(method:, endpoint:, **options)
response = HTTP
.timeout(@plex_timeout)
.headers(
"X-Plex-Token" => ENV["PLEX_TOKEN"],
"Accept" => "application/json",
)
.public_send(method, "#{@plex_addr}#{endpoint}", **options)
retries_count = 0

JSON.parse(response)
# Keep trying request if it fails until number of retries have been exhausted
loop do
url = "#{@plex_addr}#{endpoint}"

log(method: method, url: url)

response = HTTP
.timeout(@plex_timeout)
.headers(
"X-Plex-Token" => @plex_token,
"Accept" => "application/json",
)
.public_send(method, url, **options)

return JSON.parse(response)
rescue HTTP::Error => e
raise(e) if retries_count >= @plex_retries_count

retries_count += 1
end
end

# Set metric values and reset all other labels that werenn't passed in
Expand Down
Loading