From 7fce396e66096f8ccd41997e41b56219be2bce48 Mon Sep 17 00:00:00 2001 From: James Hu Date: Sun, 12 Nov 2023 16:45:13 -0800 Subject: [PATCH] Add optimizations and setting to retry failed Plex requests (#13) --- .github/workflows/docker.yml | 3 ++ README.md | 2 ++ docker-compose.yml | 2 ++ lib/middleware/collector.rb | 66 ++++++++++++++++++++++++++++-------- 4 files changed, 59 insertions(+), 14 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 356e630..73ee663 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -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 @@ -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 diff --git a/README.md b/README.md index 9421738..e3f0b39 100644 --- a/README.md +++ b/README.md @@ -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`) diff --git a/docker-compose.yml b/docker-compose.yml index 9fe604b..267c3f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -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 diff --git a/lib/middleware/collector.rb b/lib/middleware/collector.rb index 3dd88aa..20689dc 100644 --- a/lib/middleware/collector.rb +++ b/lib/middleware/collector.rb @@ -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" @@ -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 @@ -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 } @@ -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