Skip to content

Commit

Permalink
more 10
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesward committed Jan 31, 2024
1 parent 7df7dda commit 30e556a
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 14 deletions.
71 changes: 68 additions & 3 deletions java-loom/src/main/java/Main.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import com.sun.management.OperatingSystemMXBean;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import java.util.concurrent.StructuredTaskScope;

Expand Down Expand Up @@ -218,13 +226,70 @@ record TimedResponse(Instant instant, HttpResponse<String> response) {
}
}

List<String> results() throws ExecutionException, InterruptedException {
public String scenario10() throws NoSuchAlgorithmException, InterruptedException {
var id = UUID.randomUUID().toString();

Supplier<String> blocker = () -> {
try (var scope = new StructuredTaskScope.ShutdownOnSuccess<HttpResponse<String>>()) {
var req = HttpRequest.newBuilder(url.resolve(STR."/10?\{id}")).build();
var messageDigest = MessageDigest.getInstance("SHA-512");

scope.fork(() -> client.send(req, HttpResponse.BodyHandlers.ofString()));
scope.fork(() -> {
var result = new byte[512];
new Random().nextBytes(result);
while (!Thread.interrupted())
result = messageDigest.digest(result);
return null;
});
scope.join();
return scope.result().body();
} catch (ExecutionException | InterruptedException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
};

class Recursive<I> {
public I func;
}

Recursive<Supplier<String>> recursive = new Recursive<>();
recursive.func = () -> {
var osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class);
var load = osBean.getProcessCpuLoad() * osBean.getAvailableProcessors();
var req = HttpRequest.newBuilder(url.resolve(STR."/10?\{id}=\{load}")).build();
try {
var resp = client.send(req, HttpResponse.BodyHandlers.ofString());
if ((resp.statusCode() >= 200) && (resp.statusCode() < 300)) {
return resp.body();
}
else if ((resp.statusCode() >= 300) && (resp.statusCode() < 400)) {
Thread.sleep(1000);
return recursive.func.get();
}
else {
throw new RuntimeException(resp.body());
}
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
};

try (var scope = new StructuredTaskScope<String>()) {
scope.fork(blocker::get);
var task = scope.fork(recursive.func::get);
scope.join();
return task.get();
}
}

List<String> results() throws ExecutionException, InterruptedException, NoSuchAlgorithmException {
return List.of(scenario1(), scenario2(), scenario3(), scenario4(), scenario5(), scenario6(), scenario7(), scenario8(), scenario9());
//return List.of(scenario9());
//return List.of(scenario10());
}
}

void main() throws URISyntaxException, ExecutionException, InterruptedException {
void main() throws URISyntaxException, ExecutionException, InterruptedException, NoSuchAlgorithmException {
var scenarios = new Scenarios(new URI("http://localhost:8080"));
scenarios.results().forEach(System.out::println);
}
Expand Down
2 changes: 1 addition & 1 deletion kotlin-coroutines/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ dependencies {
testImplementation("io.kotest:kotest-runner-junit5:5.8.0")
testImplementation("io.kotest:kotest-assertions-core:5.8.0")
testImplementation("io.kotest.extensions:kotest-extensions-testcontainers:2.0.2")
testRuntimeOnly("org.slf4j:slf4j-simple:2.0.11")
runtimeOnly("org.slf4j:slf4j-simple:2.0.11")
}

tasks.withType<Test>().configureEach {
Expand Down
50 changes: 50 additions & 0 deletions kotlin-coroutines/src/main/kotlin/Main.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import com.sun.management.OperatingSystemMXBean
import io.ktor.client.*
import io.ktor.client.plugins.*
import io.ktor.client.request.*
Expand All @@ -6,11 +7,16 @@ import io.ktor.http.*
import kotlinx.coroutines.*
import kotlinx.coroutines.selects.select
import kotlinx.coroutines.time.delay
import java.lang.management.ManagementFactory
import java.security.MessageDigest
import java.time.Duration
import java.time.Instant
import java.util.UUID
import kotlin.random.Random

val client = HttpClient {
install(HttpTimeout)
followRedirects = false
}

// Note: Intentionally, only url handling code is shared across scenarios
Expand Down Expand Up @@ -168,6 +174,49 @@ suspend fun scenario9(url: (Int) -> String): String = coroutineScope {
letters.filterNotNull().sortedBy { it.first }.joinToString("") { it.second }
}

suspend fun scenario10(url: (Int) -> String): String = coroutineScope {
val id = UUID.randomUUID().toString()

val messageDigest = MessageDigest.getInstance("SHA-512")

suspend fun blocking() = coroutineScope {
var result = Random.nextBytes(512)
while (isActive) {
result = messageDigest.digest(result)
}
}

suspend fun blocker(): Unit = coroutineScope {
try {
select {
async { client.get(url(10) + "?$id") }.onAwait { }
async(Dispatchers.IO) { blocking() }.onAwait { }
}
} finally {
coroutineContext.cancelChildren()
}
}

suspend fun reporter(): String = coroutineScope {
val osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean::class.java)
val load = osBean.processCpuLoad * osBean.availableProcessors
val resp = client.get(url(10) + "?$id=$load")
if (resp.status.isSuccess()) {
resp.bodyAsText()
}
else if ((resp.status.value >= 300) && (resp.status.value < 400)) {
delay(1000)
reporter()
}
else {
throw Exception(resp.bodyAsText())
}
}

launch { blocker() }
reporter()
}

val scenarios = listOf(
::scenario1,
::scenario2,
Expand All @@ -178,6 +227,7 @@ val scenarios = listOf(
::scenario7,
::scenario8,
::scenario9,
::scenario10,
)

suspend fun results(url: (Int) -> String) = scenarios.map {
Expand Down
23 changes: 13 additions & 10 deletions scenario-server/src/main/scala/EasyRacerServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import scala.annotation.unused

object EasyRacerServer extends ZIOAppDefault:

private val wrong = Response.internalServerError("wrong")
private val wrong = Response(Status.InternalServerError, body = Body.fromString("wrong"))

private type SessionPromise[T] = Promise[Nothing, T]

Expand Down Expand Up @@ -267,7 +267,7 @@ object EasyRacerServer extends ZIOAppDefault:
defer:
request.url.queryParams.map.keys.headOption match
case None =>
Response.badRequest("You need to specify a query parameter")
Response(Status.BadRequest, body = Body.fromString("You need to specify a query parameter"))
case Some(id) =>
val now = Clock.instant.run

Expand All @@ -282,7 +282,7 @@ object EasyRacerServer extends ZIOAppDefault:
case Some(loadString) =>
loadString.toDoubleOption match
case None =>
Response.badRequest("load was not a double")
Response(Status.BadRequest, body = Body.fromString("load was not a double"))
case Some(load) =>
sessions.get(id).run match
case None =>
Expand All @@ -295,14 +295,17 @@ object EasyRacerServer extends ZIOAppDefault:
sessions.put(id, newData).run
Response.status(Status.Found)
else
val meanLoad = data.readings.sum / data.readings.size
ZIO.log(s"Mean load while connected to blocker = $meanLoad, Current load = $load").run
if load > 0.3 then
Response(Status.Found, body = Body.fromString(s"Load was still too high: $load"))
else if meanLoad < 0.9 then
Response.badRequest(s"A CPU was not near fully loaded - mean load = $meanLoad")
if data.readings.size < data.duration.getSeconds - 1 then
Response(Status.BadRequest, body = Body.fromString("Not enough readings"))
else
Response.text("right")
val meanLoad = data.readings.sum / data.readings.size
ZIO.log(s"Mean load while connected to blocker = $meanLoad, Current load = $load").run
if load > 0.3 then
Response(Status.Found, body = Body.fromString(s"Load was still too high: $load"))
else if meanLoad < 0.9 then
Response.badRequest(s"A CPU was not near fully loaded - mean load = $meanLoad")
else
Response.text("right")


def app(scenarios: Seq[Request => ZIO[Any, Nothing, Response]]): Routes[Any, Nothing] =
Expand Down

0 comments on commit 30e556a

Please sign in to comment.