Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

gofor it

DZone's Guide to

gofor it

· Java Zone
Free Resource

What every Java engineer should know about microservices: Reactive Microservices Architecture.  Brought to you in partnership with Lightbend.

The gofor macro

I've started working on a series of open source library code for Clojure called Dragonmark that roughly falls into three categories: utilities, a distributed CSP library, and a sample web app that demonstrates distributed CSP.

So, why?

Mostly, I think that the semantics for interprocess communication should be the same as the semantics for local communication. Clojure's core.async library provides a really nice set of APIs to communicate asynchronously, have backpressure, and in general "do the right thing."

But core.async does not provide any interprocess communication. In fact, nothing in Clojure-land does a good job of abstracting the transport layer and maintaining the semantics of core.async.

So, Dragonmark.

Making core.async less verbose

If you're going to do core.async right, there's a pattern... create a channel to receive a reply, send a message, wait for a timeout or an answer, close the channel, if the answer came from the channel, do something, else, do an error.

Using Scala and LAFuture is really easy in a for comprehension. I wanted something similar in Clojure-land, so I wrote the gofor macro.

Here's an example:

(gofor
  [a (foo channel {:thing value :other_thing other_value})]
  :let [b (+ a 1)]
  [c (baz other_channel)
   d (moose third_channel {:p b}
   :timeout 45000]
  (println a b c)
  :error (println &err &at))

The [a (foo channel {:thing value :other_thing other_value})] sends a message tochannel with {:_cmd "foo" :thing value :other_thing other_value :_return a_created_channel} and waits up to 30 seconds for an answer. If the answer doesn't arrive, the:error code is invoked and the comprehension is terminated. If the answer does come back, it's bound to a.

Next, we bind b to (a + 1).

Next, we kick off a parallel set of messages to other_channel and third_channel and wait up to 45 seconds for a response.

If we succeed, the (println a b c) code is executed.

It's a first pass at something that makes core.async more usable, especially in the case of cross-address space messaging where timeouts and failures should be expected and embraced.

Microservices for Java, explained. Revitalize your legacy systems (and your career) with Reactive Microservices Architecture, a free O'Reilly book. Brought to you in partnership with Lightbend.

Topics:

Published at DZone with permission of David Pollak. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}