diff --git a/CHANGELOG.md b/CHANGELOG.md index 0524ea872b..d900116059 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,8 @@ the release. ([#1462](https://github.com/open-telemetry/opentelemetry-demo/pull/1462)) * [loadgenerator] added loadgeneratorFloodHomepage flagd ([#1486](https://github.com/open-telemetry/opentelemetry-demo/pull/1486)) +* [adservice] add adServiceHighCpu feature flag + ([#1510](https://github.com/open-telemetry/opentelemetry-demo/pull/1510)) ## 1.8.0 diff --git a/src/adservice/src/main/java/oteldemo/AdService.java b/src/adservice/src/main/java/oteldemo/AdService.java index 4bdd81ac86..7963c8055d 100644 --- a/src/adservice/src/main/java/oteldemo/AdService.java +++ b/src/adservice/src/main/java/oteldemo/AdService.java @@ -35,6 +35,7 @@ import oteldemo.Demo.AdRequest; import oteldemo.Demo.AdResponse; import oteldemo.problempattern.GarbageCollectionTrigger; +import oteldemo.problempattern.CPULoad; import dev.openfeature.contrib.providers.flagd.FlagdOptions; import dev.openfeature.contrib.providers.flagd.FlagdProvider; import dev.openfeature.sdk.Client; @@ -130,6 +131,7 @@ private static class AdServiceImpl extends oteldemo.AdServiceGrpc.AdServiceImplB private static final String ADSERVICE_FAILURE = "adServiceFailure"; private static final String ADSERVICE_MANUAL_GC_FEATURE_FLAG = "adServiceManualGc"; + private static final String ADSERVICE_HIGH_CPU_FEATURE_FLAG = "adServiceHighCpu"; private AdServiceImpl() {} @@ -143,6 +145,8 @@ private AdServiceImpl() {} @Override public void getAds(AdRequest req, StreamObserver responseObserver) { AdService service = AdService.getInstance(); + CPULoad cpuload = CPULoad.getInstance(); + cpuload.execute(getFeatureFlagEnabled(ADSERVICE_HIGH_CPU_FEATURE_FLAG)); // get the current span in context Span span = Span.current(); diff --git a/src/adservice/src/main/java/oteldemo/problempattern/CPULoad.java b/src/adservice/src/main/java/oteldemo/problempattern/CPULoad.java new file mode 100644 index 0000000000..178f773370 --- /dev/null +++ b/src/adservice/src/main/java/oteldemo/problempattern/CPULoad.java @@ -0,0 +1,116 @@ +/* +* Copyright The OpenTelemetry Authors +* SPDX-License-Identifier: Apache-2.0 +*/ +package oteldemo.problempattern; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import io.grpc.ManagedChannelBuilder; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * This class is designed to simulate a high CPU load scenario. + * It contains methods to start and stop a specified number of worker threads designed to + * perform CPU-intensive calculations. + */ +public class CPULoad { + private static final Logger logger = LogManager.getLogger(CPULoad.class.getName()); + private static final int THREAD_COUNT = 4; + private boolean running = false; + private final List runningWorkers = new ArrayList<>(); + + private static CPULoad instance; + + /** + * Singleton pattern to get the instance of CPULoad. + * @return The singleton instance of CPULoad. + */ + public static CPULoad getInstance() { + if (instance == null) { + instance = new CPULoad(); + } + return instance; + } + + /** + * Starts or stops the CPU load generation based on the input parameter. + * If enabled, it launches worker threads. If disabled, it stops any running threads. + * + * @param enabled Flag to start (true) or stop (false) the CPU load simulation. + */ + public void execute(Boolean enabled) { + if (enabled) { + logger.info("High CPU-Load problempattern enabled"); + if (!running) { + spawnLoadWorkers(THREAD_COUNT); + running = true; + } + } else { + running = false; + stopWorkers(); + } + } + + /** + * Creates and starts a specified number of Logarithmizer threads to simulate CPU load. + * + * @param threadCount The number of threads to be started. + */ + private void spawnLoadWorkers(int threadCount) { + synchronized(runningWorkers) { + for (int i = 0; i < threadCount; i++) { + Logarithmizer logarithmizer = new Logarithmizer(); + Thread thread = new Thread(logarithmizer); + thread.setDaemon(true); + thread.start(); + runningWorkers.add(logarithmizer); + } + } + } + + /** + * Signals all running Logarithmizer threads to stop and clears the list of running workers. + */ + private void stopWorkers() { + synchronized(runningWorkers) { + for (Logarithmizer logarithmizer : runningWorkers) { + logarithmizer.setShouldRun(false); + } + runningWorkers.clear(); + } + } + + /** + * Inner class representing a worker focused on calculating logarithms to consume CPU resources. + */ + private static class Logarithmizer implements Runnable { + + private volatile boolean shouldRun = true; + + /** + * Continuously calculates the logarithm of the current system time until + * requested to stop. + */ + @Override + public void run() { + while (shouldRun) { + Math.log(System.currentTimeMillis()); + } + } + + /** + * Sets the shouldRun flag to control whether this Logarithmizer should continue + * to run. + * + * @param shouldRun A boolean flag to continue (true) or stop (false) the logarithm computation. + */ + public void setShouldRun(boolean shouldRun) { + this.shouldRun = shouldRun; + } + } +} diff --git a/src/flagd/demo.flagd.json b/src/flagd/demo.flagd.json index 6d2dac0d83..d4c38a390c 100644 --- a/src/flagd/demo.flagd.json +++ b/src/flagd/demo.flagd.json @@ -28,6 +28,15 @@ }, "defaultVariant": "off" }, + "adServiceHighCpu": { + "description": "Triggers high cpu load in the ad service", + "state": "ENABLED", + "variants": { + "on": true, + "off": false + }, + "defaultVariant": "off" + }, "adServiceFailure": { "description": "Fail ad service", "state": "ENABLED",