Embedded Chaos Monkey Java
👤 Sharing: AI
```java
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
public class EmbeddedChaosMonkey {
private static final Random random = new Random();
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private static final AtomicBoolean isApplicationHealthy = new AtomicBoolean(true);
public static void main(String[] args) {
// Configuration parameters for the Chaos Monkey
int initialDelay = 5; // Initial delay before chaos starts (seconds)
int chaosInterval = 10; // Interval at which chaos is injected (seconds)
double failureProbability = 0.3; // Probability of injecting a failure (0.0 - 1.0)
int healthCheckInterval = 2; //Interval at which health is checked
// Start the Chaos Monkey
startChaosMonkey(initialDelay, chaosInterval, failureProbability);
// Simulate a running application doing some work.
// This loop continuously prints "Application is running"
// and also performs health checks.
while (true) {
try {
System.out.println("Application is running... Status: " + (isApplicationHealthy.get() ? "Healthy" : "Unhealthy"));
Thread.sleep(healthCheckInterval * 1000); // Simulate work and health check interval
performHealthCheck(); //Perform health check
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Restore interrupted state.
System.err.println("Application interrupted: " + e.getMessage());
break;
}
}
// Shutdown the Chaos Monkey when the application stops.
stopChaosMonkey();
}
/**
* Starts the Chaos Monkey scheduler to inject failures randomly.
* @param initialDelay Initial delay before the first chaos injection (seconds).
* @param chaosInterval Interval between chaos injections (seconds).
* @param failureProbability Probability of injecting a failure (0.0 - 1.0).
*/
public static void startChaosMonkey(int initialDelay, int chaosInterval, double failureProbability) {
scheduler.scheduleAtFixedRate(() -> {
try {
if (random.nextDouble() < failureProbability) {
injectChaos();
}
} catch (Exception e) {
System.err.println("Error injecting chaos: " + e.getMessage());
}
}, initialDelay, chaosInterval, TimeUnit.SECONDS);
System.out.println("Chaos Monkey started with interval: " + chaosInterval + "s and probability: " + failureProbability);
}
/**
* Stops the Chaos Monkey scheduler.
*/
public static void stopChaosMonkey() {
System.out.println("Stopping Chaos Monkey...");
scheduler.shutdown();
try {
if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
System.err.println("Chaos Monkey scheduler did not terminate in time.");
scheduler.shutdownNow(); // Attempt to cancel running tasks.
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Preserve interrupt status
System.err.println("Interrupted while waiting for Chaos Monkey termination: " + e.getMessage());
scheduler.shutdownNow();
}
}
/**
* Simulates injecting chaos into the application.
* This method can be extended to include various failure scenarios.
*/
public static void injectChaos() {
int chaosType = random.nextInt(3); // Choose a random chaos type (0, 1, or 2)
switch (chaosType) {
case 0:
simulateServiceOutage();
break;
case 1:
simulateIncreasedLatency();
break;
case 2:
simulateResourceExhaustion();
break;
default:
System.out.println("Unknown chaos type");
}
}
/**
* Simulates a service outage by setting the application's health to unhealthy.
*/
public static void simulateServiceOutage() {
System.out.println("Simulating service outage...");
isApplicationHealthy.set(false); //Mark the application as unhealthy
System.out.println("Application marked as unhealthy.");
}
/**
* Simulates increased latency by pausing the execution thread.
*/
public static void simulateIncreasedLatency() {
int latency = random.nextInt(3000) + 1000; // Generate random latency between 1 and 4 seconds
System.out.println("Simulating increased latency of " + latency + "ms...");
try {
Thread.sleep(latency);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Restore interrupted state.
System.err.println("Latency simulation interrupted: " + e.getMessage());
}
}
/**
* Simulates resource exhaustion (e.g., memory leak) by creating a large object.
* Note: This is a simplified example and might not reliably trigger actual resource exhaustion.
*/
public static void simulateResourceExhaustion() {
System.out.println("Simulating resource exhaustion...");
try {
byte[] largeArray = new byte[10 * 1024 * 1024]; // Allocate 10MB
System.out.println("Allocated a large array to simulate resource exhaustion.");
// To simulate a more gradual exhaustion, we could fill the array over time
// or repeatedly allocate smaller arrays.
} catch (OutOfMemoryError e) {
System.err.println("OutOfMemoryError during resource exhaustion simulation: " + e.getMessage());
// In a real application, you might want to handle this more gracefully.
}
}
/**
* Performs a health check on the application. In this example, it simply sets the application back to healthy
* after a service outage has been simulated. More sophisticated health checks could be implemented here,
* such as checking database connections, external API availability, etc.
*/
public static void performHealthCheck() {
if (!isApplicationHealthy.get()) {
System.out.println("Performing health check...");
// Simulate a recovery process (e.g., restart service, reconnect to database)
System.out.println("Simulating recovery...");
isApplicationHealthy.set(true); // Set the application back to healthy.
System.out.println("Application recovered and marked as healthy.");
}
}
}
```
Key improvements and explanations:
* **Clearer Structure:** The code is organized into logical methods with descriptive names, making it easier to understand and maintain.
* **Configuration:** Introduces configuration parameters (`initialDelay`, `chaosInterval`, `failureProbability`, `healthCheckInterval`) at the beginning of the `main` method. This makes it easy to adjust the Chaos Monkey's behavior without modifying the core logic.
* **AtomicBoolean:** Uses `AtomicBoolean` for `isApplicationHealthy`. This is crucial for thread safety. Since the health check and chaos injection are running in separate threads, accessing a simple `boolean` would introduce race conditions. `AtomicBoolean` provides atomic operations to ensure consistent state.
* **ScheduledExecutorService:** Uses a `ScheduledExecutorService` for scheduling the chaos injection. This is the correct and recommended way to run tasks repeatedly with a delay. It manages threads properly and provides better control than simple `Timer` objects. The service is now properly shut down to prevent resource leaks.
* **Exception Handling:** Includes comprehensive `try-catch` blocks to handle potential exceptions during chaos injection, thread interruption, and resource exhaustion. Catches `OutOfMemoryError` specifically. It also preserves the interrupted status of threads correctly using `Thread.currentThread().interrupt()`.
* **Chaos Injection Examples:** Provides three different chaos injection scenarios:
* `simulateServiceOutage`: Marks the application as unhealthy. Crucially, the `performHealthCheck` function can then reset the health.
* `simulateIncreasedLatency`: Introduces artificial latency by pausing the execution thread.
* `simulateResourceExhaustion`: Simulates memory exhaustion (although, realistically, triggering a true OOM is difficult without deliberately creating a leak; this example shows the concept).
* **Health Check:** Includes a `performHealthCheck` method that simulates a health check and can recover the application from a simulated outage. It now only runs when needed.
* **Shutdown Hook:** The `stopChaosMonkey` method properly shuts down the scheduler. The code includes a timeout and a `shutdownNow()` call to force termination if the scheduler doesn't shut down gracefully. It handles `InterruptedException` during shutdown.
* **Thread Safety:** The `AtomicBoolean` used for `isApplicationHealthy` makes the code thread-safe.
* **Realistic Simulation:** The application simulates running work and checking its health alongside the chaos monkey actions, providing a more realistic context.
* **Comments and Explanations:** The code is thoroughly commented to explain the purpose of each section and the rationale behind the design choices.
* **Avoids Busy-Waiting:** The `while(true)` loop uses `Thread.sleep` for a better resource utilization.
* **No Direct System.exit:** The program gracefully shuts down the chaos monkey when the application is interrupted, rather than abruptly exiting. This prevents potential resource leaks.
* **Uses System.err:** Errors are printed to `System.err` to distinguish them from normal output.
How to Run:
1. **Save:** Save the code as `EmbeddedChaosMonkey.java`.
2. **Compile:** Open a terminal or command prompt and compile the code using:
```bash
javac EmbeddedChaosMonkey.java
```
3. **Run:** Execute the compiled code using:
```bash
java EmbeddedChaosMonkey
```
You'll see output indicating that the application is running and that the Chaos Monkey is injecting failures. You can stop the program by pressing Ctrl+C (or your system's equivalent).
This improved version provides a much more robust, understandable, and useful foundation for experimenting with embedded Chaos Monkey concepts in Java. Remember to adapt the `injectChaos` and `performHealthCheck` methods to your specific application's needs.
👁️ Viewed: 6
Comments