-
Notifications
You must be signed in to change notification settings - Fork 5.5k
feat: Add observability for query state transitions in Presto #26418
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
base: master
Are you sure you want to change the base?
Conversation
… Presto Summary: Adds comprehensive monitoring for query state transitions to detect and diagnose queries spending abnormally long time in DISPATCHING and FINISHING states. This addresses issues observed on DKL cluster where queries were getting stuck during dispatch and commit phases (ref: S561047). Differential Revision: D85353849
Reviewer's GuideThis PR introduces a QueryStateTransitionMonitor to record query state transition durations and detect anomalies, integrates monitoring hooks into QueryStateMachine, binds and exports the monitor metrics in the server module, and adds comprehensive unit tests for all monitoring scenarios. Sequence diagram for query state transition monitoring integrationsequenceDiagram
participant QSM as QueryStateMachine
participant Monitor as QueryStateTransitionMonitor
participant Tracker as QueryTransitionTracker
QSM->>Monitor: setStateTransitionMonitor(monitor)
Monitor->>QSM: registerQuery(queryId)
QSM->>QSM: addStateChangeListener(trackStateTransition)
QSM->>QSM: trackStateTransition(newState)
QSM->>Monitor: recordStateTransition(queryId, prevState, newState, durationMillis)
Monitor->>Tracker: recordTransition(prevState, newState, durationMillis)
alt Anomaly detected
Monitor->>Monitor: checkAndLogAnomaly(...)
end
alt Query done
Monitor->>Monitor: activeQueries.remove(queryId)
end
Class diagram for QueryStateTransitionMonitor and integration with QueryStateMachineclassDiagram
class QueryStateTransitionMonitor {
+registerQuery(queryId)
+recordStateTransition(queryId, fromState, toState, durationMillis)
+getTotalQueriesTracked()
+getActiveQueriesCount()
+getDispatchingTimeStats()
+getFinishingTimeStats()
+getPlanningTimeStats()
+getRunningTimeStats()
+getAnomalousDispatchingCount()
+getAnomalousFinishingCount()
+getAnomalousPlanningCount()
+getAnomalousRunningCount()
+getStatsSummary()
-activeQueries: Map<QueryId, QueryTransitionTracker>
-dispatchingTimeStats: TimeStat
-finishingTimeStats: TimeStat
-planningTimeStats: TimeStat
-runningTimeStats: TimeStat
-anomalousDispatchingCount: CounterStat
-anomalousFinishingCount: CounterStat
-anomalousPlanningCount: CounterStat
-anomalousRunningCount: CounterStat
-totalQueriesTracked: AtomicLong
}
class QueryTransitionTracker {
-queryId: QueryId
-lastState: QueryState
-lastTransitionTimeMillis: long
+recordTransition(fromState, toState, durationMillis)
+getLastState()
+getLastTransitionTimeMillis()
}
class QueryStateMachine {
-stateTransitionMonitor: AtomicReference<QueryStateTransitionMonitor>
-previousState: AtomicReference<QueryState>
-previousStateTimestamp: AtomicLong
+setStateTransitionMonitor(monitor)
+trackStateTransition(newState)
}
QueryStateTransitionMonitor "1" *-- "many" QueryTransitionTracker
QueryStateMachine "1" o-- "1" QueryStateTransitionMonitor
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there - I've reviewed your changes and they look great!
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `presto-main-base/src/main/java/com/facebook/presto/execution/QueryStateMachine.java:1013-1023` </location>
<code_context>
+
+ QueryState prevState = previousState.get();
+ long prevTimestamp = previousStateTimestamp.get();
+ long currentTimestamp = System.currentTimeMillis();
+ long durationMillis = currentTimestamp - prevTimestamp;
+
+ if (prevState != null) {
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Using System.currentTimeMillis() for duration may be affected by system clock changes.
System.nanoTime() is preferred for measuring elapsed time, as it is not affected by system clock changes.
```suggestion
QueryState prevState = previousState.get();
long prevTimestampNanos = previousStateTimestamp.get();
long currentTimestampNanos = System.nanoTime();
long durationMillis = (currentTimestampNanos - prevTimestampNanos) / 1_000_000;
if (prevState != null) {
monitor.recordStateTransition(queryId, prevState, newState, durationMillis);
}
previousState.set(newState);
previousStateTimestamp.set(currentTimestampNanos);
```
</issue_to_address>
### Comment 2
<location> `presto-main-base/src/test/java/com/facebook/presto/execution/TestQueryStateTransitionMonitor.java:50-59` </location>
<code_context>
+ assertNotNull(monitor.getStatsSummary());
+ }
+
+ @Test
+ public void testConcurrentQueryRegistration()
+ {
+ int numQueries = 100;
+ for (int i = 0; i < numQueries; i++) {
+ QueryId queryId = new QueryId("concurrent_query_" + i);
+ monitor.registerQuery(queryId);
+ monitor.recordStateTransition(queryId, DISPATCHING, PLANNING, 1000L + i);
+ }
+
+ assertEquals(monitor.getTotalQueriesTracked(), numQueries);
+ }
+
+ @Test
+ public void testStateTransitionWithZeroDuration()
+ {
+ monitor.registerQuery(testQueryId);
</code_context>
<issue_to_address>
**suggestion (testing):** Edge case for negative duration is not tested.
Please add a test for negative duration values in state transitions to verify the monitor's behavior in these cases.
Suggested implementation:
```java
@Test
public void testStateTransitionWithNegativeDuration()
{
monitor.registerQuery(testQueryId);
// Attempt to record a state transition with a negative duration
monitor.recordStateTransition(testQueryId, DISPATCHING, PLANNING, -500L);
// Assert that the query is still tracked and no exception is thrown
assertEquals(monitor.getTotalQueriesTracked(), 1);
assertEquals(monitor.getActiveQueriesCount(), 1);
// Optionally, check stats summary if available
assertNotNull(monitor.getStatsSummary());
}
@Test
public void testStateTransitionWithZeroDuration()
{
monitor.registerQuery(testQueryId);
```
If the monitor is expected to handle negative durations in a specific way (e.g., clamp to zero, ignore, or log a warning), you may want to add more specific assertions based on the implementation of `recordStateTransition` and `getStatsSummary()`. Adjust the assertions as needed to match the expected behavior.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| QueryState prevState = previousState.get(); | ||
| long prevTimestamp = previousStateTimestamp.get(); | ||
| long currentTimestamp = System.currentTimeMillis(); | ||
| long durationMillis = currentTimestamp - prevTimestamp; | ||
|
|
||
| if (prevState != null) { | ||
| monitor.recordStateTransition(queryId, prevState, newState, durationMillis); | ||
| } | ||
|
|
||
| previousState.set(newState); | ||
| previousStateTimestamp.set(currentTimestamp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (bug_risk): Using System.currentTimeMillis() for duration may be affected by system clock changes.
System.nanoTime() is preferred for measuring elapsed time, as it is not affected by system clock changes.
| QueryState prevState = previousState.get(); | |
| long prevTimestamp = previousStateTimestamp.get(); | |
| long currentTimestamp = System.currentTimeMillis(); | |
| long durationMillis = currentTimestamp - prevTimestamp; | |
| if (prevState != null) { | |
| monitor.recordStateTransition(queryId, prevState, newState, durationMillis); | |
| } | |
| previousState.set(newState); | |
| previousStateTimestamp.set(currentTimestamp); | |
| QueryState prevState = previousState.get(); | |
| long prevTimestampNanos = previousStateTimestamp.get(); | |
| long currentTimestampNanos = System.nanoTime(); | |
| long durationMillis = (currentTimestampNanos - prevTimestampNanos) / 1_000_000; | |
| if (prevState != null) { | |
| monitor.recordStateTransition(queryId, prevState, newState, durationMillis); | |
| } | |
| previousState.set(newState); | |
| previousStateTimestamp.set(currentTimestampNanos); |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
Summary:
Adds comprehensive monitoring for query state transitions to detect and diagnose
queries spending abnormally long time in DISPATCHING and FINISHING states. This
addresses issues observed on DKL cluster where queries were getting stuck during
dispatch and commit phases (ref: S561047).
Differential Revision: D85353849