Copilot commented on code in PR #12383:
URL: https://github.com/apache/apisix/pull/12383#discussion_r2218129788


##########
apisix/plugins/prometheus/exporter.lua:
##########
@@ -498,10 +509,60 @@ local function collect(ctx, stream_only)
         end
     end
 
+    return core.table.concat(prometheus:metric_data())
+end
+
+
+local function exporter_timer(premature)
+    if premature then
+        return
+    end
+
+    local refresh_interval = DEFAULT_REFRESH_INTERVAL
+    local attr = plugin.plugin_attr("prometheus")
+    if attr and attr.refresh_interval then
+        refresh_interval = attr.refresh_interval
+    end
+
+    ngx.timer.at(refresh_interval, exporter_timer)
+
+    if exporter_timer_running then
+        core.log.warn("Previous calculation still running, skipping")
+        return
+    end
+
+    exporter_timer_running = true
+
+    local ok, res = pcall(collect)
+    if not ok then
+        core.log.error("Failed to collect metrics: ", res)
+        return
+    end
+    ngx.shared["prometheus-metrics"]:set(CACHED_METRICS_KEY, res)

Review Comment:
   Missing error handling for shared dictionary operation. The set operation 
could fail if the shared dictionary is full or unavailable, which should be 
logged.
   ```suggestion
       local success, err = 
ngx.shared["prometheus-metrics"]:set(CACHED_METRICS_KEY, res)
       if not success then
           core.log.error("Failed to set metrics in shared dictionary: ", err)
       end
   ```



##########
apisix/plugins/prometheus/exporter.lua:
##########
@@ -498,10 +509,60 @@ local function collect(ctx, stream_only)
         end
     end
 
+    return core.table.concat(prometheus:metric_data())
+end
+
+
+local function exporter_timer(premature)
+    if premature then
+        return
+    end
+
+    local refresh_interval = DEFAULT_REFRESH_INTERVAL
+    local attr = plugin.plugin_attr("prometheus")
+    if attr and attr.refresh_interval then
+        refresh_interval = attr.refresh_interval
+    end
+
+    ngx.timer.at(refresh_interval, exporter_timer)
+
+    if exporter_timer_running then
+        core.log.warn("Previous calculation still running, skipping")
+        return
+    end
+
+    exporter_timer_running = true
+
+    local ok, res = pcall(collect)
+    if not ok then
+        core.log.error("Failed to collect metrics: ", res)
+        return
+    end
+    ngx.shared["prometheus-metrics"]:set(CACHED_METRICS_KEY, res)
+
+    exporter_timer_running = false
+end
+
+function init_exporter_timer()
+    if process.type() ~= "privileged agent" then
+        return
+    end
+
+    ngx.timer.at(0, exporter_timer)
+end
+
+local function get_cached_metrics()
+    if not prometheus or not metrics then
+        core.log.error("prometheus: plugin is not initialized, please make 
sure ",
+                     " 'prometheus_metrics' shared dict is present in nginx 
template")
+        return 500, {message = "An unexpected error occurred"}
+    end
+
+    local cached_metrics_text = 
ngx.shared["prometheus-metrics"]:get(CACHED_METRICS_KEY)

Review Comment:
   Missing error handling and fallback for shared dictionary get operation. If 
the cached data is not available or expired, the function should handle this 
gracefully rather than returning nil metrics.
   ```suggestion
       local cached_metrics_text = 
ngx.shared["prometheus-metrics"]:get(CACHED_METRICS_KEY)
       if not cached_metrics_text then
           core.log.error("Failed to retrieve cached metrics: data is nil or 
expired")
           core.response.set_header("content_type", "text/plain")
           return 500, "Failed to retrieve metrics: no data available"
       end
   ```



##########
apisix/plugins/prometheus/exporter.lua:
##########
@@ -498,10 +509,60 @@ local function collect(ctx, stream_only)
         end
     end
 
+    return core.table.concat(prometheus:metric_data())
+end
+
+
+local function exporter_timer(premature)
+    if premature then
+        return
+    end
+
+    local refresh_interval = DEFAULT_REFRESH_INTERVAL
+    local attr = plugin.plugin_attr("prometheus")
+    if attr and attr.refresh_interval then
+        refresh_interval = attr.refresh_interval
+    end
+
+    ngx.timer.at(refresh_interval, exporter_timer)
+
+    if exporter_timer_running then
+        core.log.warn("Previous calculation still running, skipping")
+        return
+    end
+
+    exporter_timer_running = true
+
+    local ok, res = pcall(collect)
+    if not ok then
+        core.log.error("Failed to collect metrics: ", res)
+        return
+    end
+    ngx.shared["prometheus-metrics"]:set(CACHED_METRICS_KEY, res)
+
+    exporter_timer_running = false

Review Comment:
   The exporter_timer_running flag is not thread-safe. In a multi-worker 
environment, this boolean check and assignment could lead to race conditions. 
Consider using an atomic operation or shared dictionary for thread-safe 
synchronization.
   ```suggestion
       local shared_dict = ngx.shared["prometheus-metrics"]
       local is_running, err = shared_dict:get("exporter_timer_running")
       if is_running then
           core.log.warn("Previous calculation still running, skipping")
           return
       end
   
       local success, err = shared_dict:set("exporter_timer_running", true)
       if not success then
           core.log.error("Failed to set exporter_timer_running flag: ", err)
           return
       end
   
       local ok, res = pcall(collect)
       if not ok then
           core.log.error("Failed to collect metrics: ", res)
           shared_dict:delete("exporter_timer_running")
           return
       end
       ngx.shared["prometheus-metrics"]:set(CACHED_METRICS_KEY, res)
   
       shared_dict:delete("exporter_timer_running")
   ```



##########
apisix/plugins/prometheus/exporter.lua:
##########
@@ -498,10 +509,60 @@ local function collect(ctx, stream_only)
         end
     end
 
+    return core.table.concat(prometheus:metric_data())
+end
+
+
+local function exporter_timer(premature)
+    if premature then
+        return
+    end
+
+    local refresh_interval = DEFAULT_REFRESH_INTERVAL
+    local attr = plugin.plugin_attr("prometheus")
+    if attr and attr.refresh_interval then
+        refresh_interval = attr.refresh_interval
+    end
+
+    ngx.timer.at(refresh_interval, exporter_timer)
+
+    if exporter_timer_running then
+        core.log.warn("Previous calculation still running, skipping")
+        return
+    end
+
+    exporter_timer_running = true
+
+    local ok, res = pcall(collect)
+    if not ok then
+        core.log.error("Failed to collect metrics: ", res)
+        return
+    end
+    ngx.shared["prometheus-metrics"]:set(CACHED_METRICS_KEY, res)

Review Comment:
   Hard-coded shared dictionary name 'prometheus-metrics' should be defined as 
a constant at the module level for better maintainability and consistency.
   ```suggestion
       ngx.shared[PROMETHEUS_METRICS_DICT]:set(CACHED_METRICS_KEY, res)
   ```



##########
apisix/plugins/prometheus/exporter.lua:
##########
@@ -498,10 +509,60 @@ local function collect(ctx, stream_only)
         end
     end
 
+    return core.table.concat(prometheus:metric_data())
+end
+
+
+local function exporter_timer(premature)
+    if premature then
+        return
+    end
+
+    local refresh_interval = DEFAULT_REFRESH_INTERVAL
+    local attr = plugin.plugin_attr("prometheus")
+    if attr and attr.refresh_interval then
+        refresh_interval = attr.refresh_interval
+    end
+
+    ngx.timer.at(refresh_interval, exporter_timer)
+
+    if exporter_timer_running then
+        core.log.warn("Previous calculation still running, skipping")
+        return
+    end
+
+    exporter_timer_running = true

Review Comment:
   The exporter_timer_running flag should be reset to false in case of early 
returns or errors to prevent the timer from being permanently disabled.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@apisix.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to