-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature: add shutdown notifier (#28)
* feature: add shutdown notifier * feature: add shutdown notification model * little refactor * use agent ID as request param * fix test * test: fix callback concurrency issue * refactor: ShutdownHookManager * use config 3.0.3-dev * make INFO final * fix test
- Loading branch information
Showing
26 changed files
with
561 additions
and
130 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
70 changes: 37 additions & 33 deletions
70
...d-agent/src/main/java/rocks/inspectit/gepard/agent/internal/identity/model/AgentInfo.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
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
123 changes: 123 additions & 0 deletions
123
...ent/src/main/java/rocks/inspectit/gepard/agent/internal/shutdown/ShutdownHookManager.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,123 @@ | ||
/* (C) 2024 */ | ||
package rocks.inspectit.gepard.agent.internal.shutdown; | ||
|
||
import com.google.common.annotations.VisibleForTesting; | ||
import java.util.*; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
/** | ||
* Responsible for executing the agents shutdown hooks in the order they are added. We should try to | ||
* keep the amount of shutdown hooks as well as the logic inside them minimal to prevent long | ||
* shutdown time. | ||
*/ | ||
public class ShutdownHookManager { | ||
private static final Logger log = LoggerFactory.getLogger(ShutdownHookManager.class); | ||
|
||
private static ShutdownHookManager instance; | ||
|
||
/** The registered shutdown hooks */ | ||
private final Set<ShutdownHook> shutdownHooks; | ||
|
||
private final AtomicBoolean isShutdown; | ||
|
||
private ShutdownHookManager() { | ||
shutdownHooks = Collections.synchronizedSet(new HashSet<>()); | ||
isShutdown = new AtomicBoolean(false); | ||
} | ||
|
||
/** | ||
* @return the singleton instance | ||
*/ | ||
public static ShutdownHookManager getInstance() { | ||
if (Objects.isNull(instance)) { | ||
instance = new ShutdownHookManager(); | ||
instance.setUpShutdownHooks(); | ||
} | ||
return instance; | ||
} | ||
|
||
/** | ||
* Adds the runnable to the shutdown hooks at the beginning of the set. During shutdown, no new | ||
* hooks can be added. | ||
*/ | ||
public void addShutdownHook(Runnable runnable) { | ||
if (!isShutdown.get()) { | ||
ShutdownHook shutdownHook = new ShutdownHook(runnable, 0); | ||
shutdownHooks.add(shutdownHook); | ||
} | ||
} | ||
|
||
/** | ||
* Adds the runnable to the shutdown hooks at the end of the set. During shutdown, no new hooks | ||
* can be added. | ||
*/ | ||
public void addShutdownHookLast(Runnable runnable) { | ||
if (!isShutdown.get()) { | ||
ShutdownHook shutdownHook = new ShutdownHook(runnable, Integer.MAX_VALUE); | ||
shutdownHooks.add(shutdownHook); | ||
} | ||
} | ||
|
||
/** Sets up the registered shutdown hooks, to be executed at shutdown */ | ||
private void setUpShutdownHooks() { | ||
Runtime.getRuntime() | ||
.addShutdownHook(new Thread(this::executeShutdownHooks, "inspectit-shutdown")); | ||
} | ||
|
||
/** Executes all registered shutdown hooks by order */ | ||
@VisibleForTesting | ||
void executeShutdownHooks() { | ||
if (!isShutdown.compareAndSet(false, true)) log.info("Cannot execute shutdown hooks twice"); | ||
else | ||
shutdownHooks.stream() | ||
.sorted(Comparator.comparingInt(ShutdownHook::getOrder)) | ||
.forEach(this::tryRunShutdownHook); | ||
} | ||
|
||
/** Try-catch-wrapper to run a shutdown hook */ | ||
private void tryRunShutdownHook(ShutdownHook shutdownHook) { | ||
try { | ||
shutdownHook.run(); | ||
} catch (Exception e) { | ||
log.error("Error while executing shutdown hook", e); | ||
} | ||
} | ||
|
||
/** | ||
* Method for testing. | ||
* | ||
* @return the current amount of registered shutdown hooks | ||
*/ | ||
public int getShutdownHookCount() { | ||
return shutdownHooks.size(); | ||
} | ||
|
||
/** Method for testing. */ | ||
public void reset() { | ||
shutdownHooks.clear(); | ||
isShutdown.set(false); | ||
} | ||
|
||
/** Internal class for ordered shutdown hooks */ | ||
private static class ShutdownHook { | ||
|
||
private final Runnable shutdownHook; | ||
|
||
private final int order; | ||
|
||
ShutdownHook(Runnable shutdownHook, int order) { | ||
this.shutdownHook = shutdownHook; | ||
this.order = order; | ||
} | ||
|
||
void run() { | ||
shutdownHook.run(); | ||
} | ||
|
||
int getOrder() { | ||
return order; | ||
} | ||
} | ||
} |
Oops, something went wrong.