Rob Bosman 21-02-2019
class FetchJokeService {
private static final Logger LOG = LoggerFactory.getLogger(FetchJokeServiceJava.class);
private static final String API_URL = "http://api.icndb.com/jokes/random?limitTo=[explicit,nerdy]"; // Chuck Norris jokes
static String fetchJoke() {
LOG.debug("fetch joke");
try {
final HttpURLConnection connection = (HttpURLConnection) new URL(API_URL).openConnection();
try {
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), UTF_8))) {
return reader.lines().collect(joining());
} catch (IOException e) {
throw new RuntimeException("Error reading from InputStream", e);
}
} finally {
connection.disconnect();
LOG.debug("fetched joke");
}
} catch (MalformedURLException e) {
throw new RuntimeException("Error in URL " + API_URL, e);
} catch (IOException e) {
throw new RuntimeException("Error connecting to " + API_URL, e);
}
}
}Hashtable
Semaphore
synchronized
volatile
Runnable
ThreadPool
ThreadLocal
InterruptedException
ConcurrentHashMap
fork / join
Future
private fun findTheAnswer(): Int {
log.debug("pondering...")
Thread.sleep(1000)
return 42
}
fun backToTheFuture() {
val executor = Executors.newFixedThreadPool(2)
val future = executor.submit(::findTheAnswer)
log.debug("are you done? - ${future.isDone}")
// do other stuff
val answer = future.get() // blocking wait
log.debug("ah, the answer is $answer.")
executor.shutdown()
}fun backToTheCompletableFuture() {
val provideAnswerCF = CompletableFuture
.supplyAsync {
log.debug("determine required processing time")
1500L
}
.thenApply { delayMillis ->
log.debug("pondering...")
Thread.sleep(delayMillis)
42
}
.thenApply { answer ->
log.debug("got it!")
answer
}
log.debug("do you know the answer? - ${provideAnswerCF.isDone}")
log.debug("ah, the answer is ${provideAnswerCF.get()}.") // blocking wait
}fun backToTheCompletableFuture() {
val provideAnswerCF = CompletableFuture
.supplyAsync {
log.debug("determine required processing time")
1500L
}
.thenApply { delayMillis ->
log.debug("pondering...")
Thread.sleep(delayMillis)
42
}
.thenApply { answer ->
log.debug("got it!")
answer
}
log.debug("do you know the answer? - ${provideAnswerCF.isDone}")
log.debug("ah, the answer is ${provideAnswerCF.get()}.") // blocking wait
}is a Functor
flatten (flatMap)
A monad is just a monoid in the category of endofunctors, what's the problem?
Rabbi Jehoeda Löw
fun run() {
log.debug("here we go")
val processControl = Semaphore(0)
val jokeRawO = Observable
.create<String> { emitter -> emitter.onNext(fetchJoke()) }
.subscribeOn(Schedulers.io())
Observable
.create<MongoClient> { emitter -> emitter.onNext(getMongoClient()) }
.subscribeOn(Schedulers.io())
.zipWith(jokeRawO,
BiFunction { mongoClient: MongoClient, jokeRaw: String ->
val joke = convertAndStore(jokeRaw, mongoClient)
mongoClient.close()
log.debug("closed MongoDB client")
joke
})
.subscribe { joke ->
log.info("'$joke'")
processControl.release()
}
log.debug("wait until all is done")
processControl.tryAcquire(3000, MILLISECONDS)
log.debug("there you are!")
}fun backToResilience() {
log.debug("here we go")
val processControl = Semaphore(0)
Single
.create<String> { emitter -> emitter.onSuccess(fetchJokeFlaky()) }
.timeout(200, MILLISECONDS)
.subscribeOn(Schedulers.io())
.doOnSuccess { jokeRaw -> if (!jokeRaw.contains("success"))
throw Throwable("invalid data: $jokeRaw") }
.doOnError { t -> log.warn("error detected: '${t.message}'", t) }
.retry(3)
.onErrorResumeNext(Single.just("fallback joke"))
.doFinally { processControl.release() }
.subscribe(
{ jokeRaw -> log.info("'$jokeRaw'") },
{ t -> log.error("an ERROR occurred", t) }
)
log.debug("wait a second...")
processControl.tryAcquire(1000, MILLISECONDS)
log.debug("there you are!")
}fun backToResilience() {
log.debug("here we go")
val processControl = Semaphore(0)
Single
.create<String> { emitter -> emitter.onSuccess(fetchJokeFlaky()) }
.timeout(200, MILLISECONDS)
.subscribeOn(Schedulers.io())
.doOnSuccess { jokeRaw -> if (!jokeRaw.contains("success"))
throw Throwable("invalid data: $jokeRaw") }
.doOnError { t -> log.warn("error detected: '${t.message}'", t) }
.retry(3)
.onErrorResumeNext(Single.just("fallback joke"))
.doFinally { processControl.release() }
.subscribe(
{ jokeRaw -> log.info("'$jokeRaw'") },
{ t -> log.error("an ERROR occurred", t) }
)
log.debug("wait a second...")
processControl.tryAcquire(1000, MILLISECONDS)
log.debug("there you are!")
}goto(label);throw new Exception();fun backToResilience() {
log.debug("here we go")
val processControl = Semaphore(0)
Single
.create<String> { emitter -> emitter.onSuccess(fetchJokeFlaky()) }
.timeout(200, MILLISECONDS)
.subscribeOn(Schedulers.io())
.doOnSuccess { jokeRaw -> if (!jokeRaw.contains("success"))
throw Throwable("invalid data: $jokeRaw") }
.doOnError { t -> log.warn("error detected: '${t.message}'", t) }
.retry(3)
.onErrorResumeNext(Single.just("fallback joke"))
.doFinally { processControl.release() }
.subscribe(
{ jokeRaw -> log.info("'$jokeRaw'") },
{ t -> log.error("an ERROR occurred", t) }
)
log.debug("wait a second...")
processControl.tryAcquire(1000, MILLISECONDS)
log.debug("there you are!")
}fun main() {
val vertx = Vertx.vertx()
CompositeFuture
.all(
CompositeFuture.all(
deployVerticle(vertx, PeanutPooper::class.java.name),
deployVerticle(vertx, Chocolatifier::class.java.name),
deployVerticle(vertx, Painter::class.java.name),
deployVerticle(vertx, LetterStamper::class.java.name),
deployVerticle(vertx, MnMPackager::class.java.name)),
CompositeFuture.all(
deployVerticle(vertx, PeanutSpeedLogger::class.java.name),
deployVerticle(vertx, HttpEventServer::class.java.name))
)
.setHandler { result ->
if (result.succeeded()) {
log.info("We have hyperdrive, captain.")
} else {
log.error("Error", result.cause())
}
}
}
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.concurrent.threadGitHub: Cerios/
ReactiveChocolate