-
-
Notifications
You must be signed in to change notification settings - Fork 196
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add tracking of heartbeat results and executions with stale hea…
…rtbeat (#432) Add tracking of heartbeat results and executions with stale heartbeat to enable acting on failing heartbeats. * Configurable number of heartbeats before considered dead (minimum is 4) * New method `schedulerBuilder.missedHeartbeatsLimit(<limit>)` * Increase default limit for missed heartbeats before considered dead from 4 to 6 * Track the number of failed heartbeats and make it available to users * New ExecutionContext method, `ctx.getCurrentlyExecuting().getHeartbeatState().getFractionDead()` * New scheduler methods for checking for stale heartbeats * `scheduler.getCurrentlyExecutingWithStaleHeartbeat()` * `scheduler.getCurrentlyExecuting().get(0).getHeartbeatState().getFractionDead()` * New `SchedulerStatsEvent`s in `StatsRegistry`: `FAILED_HEARTBEAT`, `FAILED_MULTIPLE_HEARTBEATS` (replaces `UNEXPECTED_ERROR` for failed heartbeats) * New example `HeartbeatMonitoringMain` ## Fixes * #402 ## Reminders - [x] Added/ran automated tests - [x] Update README and/or examples - [x] Ran `mvn spotless:apply`
- Loading branch information
1 parent
cadf433
commit 823c9d2
Showing
27 changed files
with
626 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
db-scheduler/src/main/java/com/github/kagkarlsson/scheduler/HeartbeatConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* | ||
* Copyright (C) Gustav Karlsson | ||
* | ||
* <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file | ||
* except in compliance with the License. You may obtain a copy of the License at | ||
* | ||
* <p>http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* <p>Unless required by applicable law or agreed to in writing, software distributed under the | ||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either | ||
* express or implied. See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.github.kagkarlsson.scheduler; | ||
|
||
import java.time.Duration; | ||
|
||
public class HeartbeatConfig { | ||
|
||
public final Duration heartbeatInterval; | ||
public final int missedHeartbeatsLimit; | ||
public final Duration maxAgeBeforeConsideredDead; | ||
|
||
public HeartbeatConfig( | ||
Duration heartbeatInterval, int missedHeartbeatsLimit, Duration maxAgeBeforeConsideredDead) { | ||
this.heartbeatInterval = heartbeatInterval; | ||
this.missedHeartbeatsLimit = missedHeartbeatsLimit; | ||
this.maxAgeBeforeConsideredDead = maxAgeBeforeConsideredDead; | ||
} | ||
} |
81 changes: 81 additions & 0 deletions
81
db-scheduler/src/main/java/com/github/kagkarlsson/scheduler/HeartbeatState.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* Copyright (C) Gustav Karlsson | ||
* | ||
* <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file | ||
* except in compliance with the License. You may obtain a copy of the License at | ||
* | ||
* <p>http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* <p>Unless required by applicable law or agreed to in writing, software distributed under the | ||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either | ||
* express or implied. See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.github.kagkarlsson.scheduler; | ||
|
||
import java.time.Duration; | ||
import java.time.Instant; | ||
|
||
public class HeartbeatState { | ||
private Clock clock; | ||
private final Instant startTime; | ||
private final HeartbeatConfig heartbeatConfig; | ||
private int heartbeatSuccessesSinceLastFailure = 0; | ||
private int heartbeatFailuresSinceLastSuccess = 0; | ||
private Instant heartbeatLastSuccess; | ||
private Instant heartbeatLastFailure; | ||
|
||
public HeartbeatState(Clock clock, Instant startTime, HeartbeatConfig heartbeatConfig) { | ||
this.clock = clock; | ||
this.startTime = startTime; | ||
this.heartbeatConfig = heartbeatConfig; | ||
heartbeatLastSuccess = startTime; | ||
} | ||
|
||
public boolean hasStaleHeartbeat() { | ||
Duration sinceLastSuccess = Duration.between(heartbeatLastSuccess, clock.now()); | ||
|
||
long heartbeatMillis = heartbeatConfig.heartbeatInterval.toMillis(); | ||
long millisUntilConsideredStale = | ||
heartbeatMillis + Math.min(10_000, (int) (heartbeatMillis * 0.25)); | ||
return heartbeatFailuresSinceLastSuccess > 0 | ||
|| sinceLastSuccess.toMillis() > millisUntilConsideredStale; | ||
} | ||
|
||
public double getFractionDead() { | ||
Duration sinceLastSuccess = Duration.between(heartbeatLastSuccess, clock.now()); | ||
return (double) sinceLastSuccess.toMillis() | ||
/ heartbeatConfig.maxAgeBeforeConsideredDead.toMillis(); | ||
} | ||
|
||
public int getFailedHeartbeats() { | ||
return heartbeatFailuresSinceLastSuccess; | ||
} | ||
|
||
public void heartbeat(boolean successful, Instant lastHeartbeatAttempt) { | ||
if (successful) { | ||
heartbeatLastSuccess = lastHeartbeatAttempt; | ||
heartbeatSuccessesSinceLastFailure++; | ||
heartbeatFailuresSinceLastSuccess = 0; | ||
} else { | ||
heartbeatLastFailure = lastHeartbeatAttempt; | ||
heartbeatSuccessesSinceLastFailure = 0; | ||
heartbeatFailuresSinceLastSuccess++; | ||
} | ||
} | ||
|
||
public String describe() { | ||
return "HeartbeatState{" | ||
+ "successesSinceLastFailure=" | ||
+ heartbeatSuccessesSinceLastFailure | ||
+ ", failuresSinceLastSuccess=" | ||
+ heartbeatFailuresSinceLastSuccess | ||
+ ", lastSuccess=" | ||
+ heartbeatLastSuccess | ||
+ ", lastFailure=" | ||
+ heartbeatLastFailure | ||
+ ", missedHeartbeatsLimit=" | ||
+ heartbeatConfig.missedHeartbeatsLimit | ||
+ '}'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.