<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[In pursuit of production minimalism]]></title><description><![CDATA[Working in online travel. Interested in functional programming, data engineering, cryptography and privacy.]]></description><link>https://ales.rocks</link><generator>RSS for Node</generator><lastBuildDate>Sun, 12 Apr 2026 00:00:11 GMT</lastBuildDate><atom:link href="https://ales.rocks/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[On ArcadeDB]]></title><description><![CDATA[I work for a Traveltech company based in Berlin. I shifted from frontend and backend positions after COVID days towards a more data-oriented position. I work mostly with BigQuery where we sink all the important data from a live-data Couchbase databas...]]></description><link>https://ales.rocks/on-arcadedb</link><guid isPermaLink="true">https://ales.rocks/on-arcadedb</guid><category><![CDATA[graph database]]></category><category><![CDATA[ArcadeDB]]></category><dc:creator><![CDATA[Aleš Najmann]]></dc:creator><pubDate>Sun, 06 Aug 2023 18:11:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/UitmwXNMHiE/upload/76942e52891fb8bc1c58901a57189a1c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I work for a Traveltech company based in Berlin. I shifted from frontend and backend positions after COVID days towards a more data-oriented position. I work mostly with BigQuery where we sink all the important data from a live-data Couchbase database cluster. I think my data pipelines brought enough attention inside of the company and they serve us well when it comes to measuring service license agreements (SLA) with our partners and tuning our services.</p>
<p>Unfortunately I don't model data as much as I'd like to. I'm mostly a user of what other teams populate to BigQuery and I haven't found Couchbase Analytic Cluster value just yet. So one day I decided to investigate what else is out there in the database world. One particular thing that can solve a lot of problems is a good graph database.</p>
<p>I need to do a short detour here. Between 2017-2018 I worked at Oracle Labs: <a target="_blank" href="https://labs.oracle.com/pls/apex/f?p=LABS:project_details:0:127">Parallel Graph Analytics (PGX)</a> team. I wasn't involved in anything related to graph database development, I worked mostly on the notebook frontend part of a multi-tenant, multi-server, scalable and secure arbitrary code execution engine - Oracle Labs Data Studio. We had a whole bunch of notebooks that demonstrated well the powers of graph modelling. And it has grown on me it seems.</p>
<p>So I did <a target="_blank" href="https://www.udemy.com/course/orientdb-getting-started/">a free OrientDB course on Udemy</a> during which I found that <a target="_blank" href="https://orientdb.org">OrientDB</a> was a dead project. I was thinking that it was a sad ending to such a nice project. Fortunately enough after short research, I found that the original author of OrientDB, <a target="_blank" href="https://github.com/lvca">Luca Garulli</a> started a company and a completely new project that extended the original idea with performance and a new business model in mind. His company is called ArcadeData Ltd. and the project name is <a target="_blank" href="https://arcadedb.com">ArcadeDB</a>.</p>
<p>What is ArcadeDB about? It is a next-generation multi-model database supporting graphs, key-value, and documents, and contains search engine, vectors and time-series datasets. Each particular model can be accessed with a protocol that serves the purpose the best. As an example, you can connect to ArcadeDB with PostgreSQL drivers when you want to use SQL to query your graph or document models, use Mongo to access document models or Redis queries to access key-value pairs etc.</p>
<p>You can imagine I got a bit excited. I decided to join the community <a target="_blank" href="https://discord.com/invite/hFXbvsFp?utm_source=Discord%20Widget&amp;utm_medium=Connect">on Discord</a> and find out if there was a way to contribute. I successfully submitted a manifest to <a target="_blank" href="https://scoop.sh">scoop</a> extras bucket. Users can now easily install ArcadeDB on their Windows development box:</p>
<pre><code class="lang-powershell">scoop bucket add extras
scoop install arcadedb
</code></pre>
<p>After this, there are two shim commands, one to use the console tool:</p>
<pre><code class="lang-powershell">arcadedb<span class="hljs-literal">-console</span>
</code></pre>
<p>and another one for launching the server:</p>
<pre><code class="lang-powershell">arcadedb<span class="hljs-literal">-server</span>
</code></pre>
<p>The current version contains a bug when rendering the ArcadeDB logo to a terminal console, so I submitted a fix to that one and with the next release, it will render correctly. It is only a cosmetic issue that does not affect any important function. Soon, I'd also like to participate in the building of a formula to install easily on MacOS X using <a target="_blank" href="https://brew.sh">homebrew</a>. Let's see if I can manage to do that.</p>
<p>My experience with the community is so far excellent. Questions and issues are addressed openly and in a friendly way. You can exchange ideas with an author and there is also a very interesting crowd of super-smart individuals participating in the development of core database features.</p>
<p>My journey with graph databases is in the early stage. ArcadeDB already helped me to spark interest and joy in this field. I plan to use not only its graph powers but also documents and even key-value capabilities to model and solve complex business problems. I'm looking forward to this adventure. And also I plan to write about it again.</p>
]]></content:encoded></item><item><title><![CDATA[Notes on Virtual Threads and Clojure]]></title><description><![CDATA[Have you heard the news? Virtual Threads implementation landed into JDK19 as a preview feature! Are you excited? No? You should be! It's an amazing addition to the Java platform.
Note this article discusses Preview version of software. Take it as an ...]]></description><link>https://ales.rocks/notes-on-virtual-threads-and-clojure</link><guid isPermaLink="true">https://ales.rocks/notes-on-virtual-threads-and-clojure</guid><category><![CDATA[Clojure]]></category><category><![CDATA[Java]]></category><category><![CDATA[concurrency]]></category><dc:creator><![CDATA[Aleš Najmann]]></dc:creator><pubDate>Fri, 13 May 2022 09:11:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/2Tnr1FMHy2g/upload/v1652112997775/yEkJkTWcR.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Have you heard the news? <a target="_blank" href="http://cr.openjdk.java.net/~rpressler/loom/loom/sol1_part1.html#right-sizing-threads">Virtual Threads</a> implementation <a target="_blank" href="https://github.com/openjdk/jdk/commit/9583e3657e43cc1c6f2101a64534564db2a9bd84">landed into JDK19 as a preview feature</a>! Are you excited? No? You should be! It's an amazing addition to the Java platform.</p>
<p>Note this article discusses Preview version of software. Take it as an inspiration, not something that is set to stone!</p>
<h2 id="heading-intro-to-project-loom-and-virtual-threads">Intro to Project Loom and Virtual Threads</h2>
<p>Virtual Threads are the most significant feature of the so-called Project Loom. </p>
<p>Project Loom was launched in 2017 by Ron Pressler and his team at Oracle. The main goal of the project was to extend the capabilities of Java Virtual Machine to address the complexity of writing highly concurrent and scalable software.</p>
<p>There is more to Project Loom than just Virtual Threads. Project wiki specifically mentioned <a target="_blank" href="https://en.wikipedia.org/wiki/Delimited_continuation">Delimited continuations</a> and 
<a target="_blank" href="https://en.wikipedia.org/wiki/Tail_call">Tail-call elimination</a>. But it's fair to say they are the most significant addition to the Java platform from the user perspective and productivity.</p>
<p>I don't want to dive deeper into delimited continuations and tail call elimination features to stay focused on the most practical matters, but it's fair to point out at least that delimited continuations seem to be quite important for the introduction of the Virtual Threads to the Java platform.</p>
<p>So what are they, and why they are so groundbreaking that it was worthy to write this post about them?</p>
<p>Traditionally, JVM threads were built around OS threads. This fact also determines their major properties:</p>
<ol>
<li>Single thread was mapped to a single OS thread</li>
<li>Blocking (waiting) on a thread caused the thread to be effectively wasted for other tasks</li>
<li>Managing threads on JVM was costly. Each thread easily uses an additional Megabytes of memory thus spawning many of them is not wise.</li>
</ol>
<p>These limitations are mitigated by introducing Virtual Threads. They no longer map one-to-one to OS threads. A single OS thread can host many thousands or more Virtual Threads without a worry about blocking issues or excessive memory demands. This requires changes to the implementation of JVM and standard library to allow an effective schedule of Virtual Threads.</p>
<p>Virtual Threads also improve a situation when limitations of OS threads were addressed by using more or less sophisticated thread pools. Experienced developers know that thread pools (of OS threads) also have significant downsides if not constrained properly.</p>
<p>Virtual Thread is represented by a class <code>java.lang.VirtualThread</code> and it extends <code>java.lang.Thread</code>. This follows the Liskov-substitution principle and allows us to easily introduce them into our existing codebases.</p>
<h2 id="heading-clojure-and-threads">Clojure and Threads</h2>
<p>It's <a target="_blank" href="https://clojure.org/about/concurrent_programming">clearly stated</a> Clojure is designed to work well together with the Java thread system. Clojure function instances even implement <code>java.util.concurrent.Callable</code> etc. so they naturally work with the Executor framework.</p>
<p>The most primitive way to do something is to launch it in a new thread like this:</p>
<pre><code class="lang-clojure">(<span class="hljs-name">.start</span> (<span class="hljs-name">Thread.</span> #(<span class="hljs-name">println</span> <span class="hljs-string">"Hello world!"</span>)))
</code></pre>
<p>Unsurprisingly there is also an API call for launching a Virtual Thread with a preview JDK (or Loom).</p>
<pre><code class="lang-clojure">(<span class="hljs-name">Thread/startVirtualThread</span> #(<span class="hljs-name">println</span> <span class="hljs-string">"Hello world!"</span>))
</code></pre>
<p>Nice! However, this is barely useful. We want concurrent processes to compose and coordinate. Clojure concurrency offers two essential mechanisms:</p>
<ul>
<li>Agents</li>
<li>Futures</li>
</ul>
<p>Let's revisit those in detail and see how we can spice it up with Loom's Virtual Threads.</p>
<h3 id="heading-agents">Agents</h3>
<p>Agents manage independent state. Their state can be changed only through submit of action. Actions are ordinary functions that take a state parameter and return a new state. Actions are dispatched using <code>send</code>, <code>send-off</code>, or <code>send-via</code> and they return immediately without waiting for completion. The action occurs asynchronously on thread-pool threads. Only one action per agent happens at a time.</p>
<p>Agents are nice because they come up with the following properties:</p>
<ul>
<li>their state is always available for a reader without blocking after dereferencing with <code>(deref an-agent)</code> or <code>@an-agent</code> shortcut</li>
<li>they can be coordinated using <code>(await an-agent)</code></li>
<li>any dispatches made during the action are held until after the state of the agent has changed</li>
<li>agents coordinate with transactions - any dispatches made during a transaction are held until it commits</li>
</ul>
<pre><code class="lang-clojure"><span class="hljs-comment">;; construct new agent</span>
(<span class="hljs-keyword">def</span> <span class="hljs-title">a-counter</span> (<span class="hljs-name"><span class="hljs-builtin-name">agent</span></span> <span class="hljs-number">0</span>))

<span class="hljs-comment">;; send it a function</span>
(<span class="hljs-name"><span class="hljs-builtin-name">send</span></span> a-counter inc)

<span class="hljs-comment">;; wait for the delivery</span>
(<span class="hljs-name"><span class="hljs-builtin-name">await</span></span> a-counter)

<span class="hljs-comment">;; reveal the state</span>
@a-counter
</code></pre>
<h4 id="heading-spicing-up-agents">Spicing up Agents</h4>
<p>Agent's dispatching functions <code>send</code> and <code>send-off</code> use default implementations of executors for submitted tasks.</p>
<p>These executors live by default inside <code>clojure.lang.Agent</code>.</p>
<ul>
<li>Dispatching function <code>send</code> uses <code>clojure.lang.Agent/pooledExecutor</code></li>
<li>Function <code>send-off</code> uses <code>clojure.lang.Agent/soloExecutor</code></li>
</ul>
<p>Both executors work by default with heavy OS threads. Even though they are good defaults we can sneak in some goodies. Loom comes with a new executor service which you can easily create using the static method on the <code>Executors</code> class. This new executor is represented by <code>ThreadPerTaskExecutor</code> class. We can replace the default pooledExecutor with this new one.</p>
<pre><code class="lang-clojure">(<span class="hljs-name"><span class="hljs-builtin-name">ns</span></span> example
  (<span class="hljs-symbol">:import</span> (<span class="hljs-name">java.util.concurrent</span> Executors)))

<span class="hljs-comment">;; Let's first define a factory that helps with spawning new Virtual Threads</span>
(<span class="hljs-keyword">defn</span> <span class="hljs-title">thread-factory</span> [name]
  (<span class="hljs-name"><span class="hljs-builtin-name">-&gt;</span></span> (<span class="hljs-name">Thread/ofVirtual</span>)
      (<span class="hljs-name">.name</span> name <span class="hljs-number">0</span>)
      (<span class="hljs-name">.factory</span>)))

<span class="hljs-comment">;; Let's swap the default executor with the new one</span>
(<span class="hljs-name">set-agent-send-executor!</span>
  (<span class="hljs-name">Executors/newThreadPerTaskExecutor</span>
    (<span class="hljs-name">thread-factory</span> <span class="hljs-string">"clojure-agent-send-pool-"</span>)))

<span class="hljs-comment">;; This code is going to be executed using Virtual Threads under the hood</span>
(<span class="hljs-keyword">def</span> <span class="hljs-title">a-counter</span> (<span class="hljs-name"><span class="hljs-builtin-name">agent</span></span> <span class="hljs-number">0</span>))
(<span class="hljs-name"><span class="hljs-builtin-name">send</span></span> a-counter inc)
(<span class="hljs-name"><span class="hljs-builtin-name">await</span></span> a-counter)
@a-counter
</code></pre>
<p>The same applies to the executor for <code>send-off</code> dispatching function.</p>
<pre><code class="lang-clojure">(<span class="hljs-name">set-agent-send-off-executor!</span>
  (<span class="hljs-name">Executors/newThreadPerTaskExecutor</span>
    (<span class="hljs-name">thread-factory</span> <span class="hljs-string">"clojure-agent-send-off-pool-"</span>)))
</code></pre>
<p>If you want to retain more control just use <code>send-via</code> where executor can be specified as a parameter:</p>
<pre><code class="lang-clojure"><span class="hljs-comment">;; Define an executor which just produce a new virtual thread for every task</span>
(<span class="hljs-keyword">def</span> <span class="hljs-title">unbounded-executor</span> (<span class="hljs-name">Executors/newThreadPerTaskExecutor</span> (<span class="hljs-name">thread-factory</span> <span class="hljs-string">"unbounded-pool-"</span>)))

(<span class="hljs-name">send-via</span> unbounded-executor a-counter dec)
(<span class="hljs-name"><span class="hljs-builtin-name">await</span></span> a-counter)
@a-counter
</code></pre>
<p>This is all you need to transparently work with Agents under the new concurrency model. Clojure seems to be well prepared for the future! Futures...</p>
<h3 id="heading-futures">Futures</h3>
<p>Future represents a value that is going to be available at an indeterminate time in the future. It can be captured and passed around as you want. In Java futures are represented by objects implementing <code>Future&lt;V&gt;</code> interface from the <code>java.util.concurrent</code> package. The brief evolution of implementations of this interface can be captured by Java's standard library:</p>
<ul>
<li>Java 1.5 introduced <code>FutureTask&lt;V&gt;</code></li>
<li>Java 1.7 introduced <code>ForkJoinTask&lt;V&gt;</code></li>
<li>As of Java 1.8 there is <code>CompletableFuture&lt;V&gt;</code></li>
</ul>
<p>Clojure contains a bunch of functions in its core library to work with futures. This is the most basic example that can demonstrate how to utilize futures in Clojure programs:</p>
<pre><code class="lang-clojure">@(<span class="hljs-name"><span class="hljs-builtin-name">future</span></span> (<span class="hljs-name">println</span> <span class="hljs-string">"Before"</span>)
         (<span class="hljs-name">java.lang.Thread/sleep</span> <span class="hljs-number">2000</span>)
         (<span class="hljs-name">println</span> <span class="hljs-string">"After 2000 ms"</span>)
         <span class="hljs-number">2000</span>)
</code></pre>
<p>As we can see Clojure futures are nice, Just dereference them similarly to <a target="_blank" href="https://clojure.org/reference/agents">agents</a> or <a target="_blank" href="https://clojuredocs.org/clojure.core/atom">atoms</a> with <code>(deref a-future)</code> or a shortcut <code>@a-future</code>. Dereferencing causes execution to block until a future value is resolved and thus available. Unfortunately, that means that the whole OS thread is blocked.</p>
<p>So what can we do to make it cheaper? Of course, Loom has our back covered with a lot cheaper Virtual Threads. Function <code>future</code> uses <code>future-call</code> function under the hood. This function references <code>clojure.lang.Agent/soloExecutor</code>. This means that if we replace this executor as we did for <code>send-off</code> above, it's all we need to do.</p>
<p>There is <a target="_blank" href="https://cljdoc.org/d/funcool/promesa">Promesa</a> library which contains constructs to deal with futures that goes way beyond the simplistic use of futures in the Clojure core library. Some functions from the Promesa library introduce arities that take executor as a parameter and use such executor to schedule computation. Passing the <code>ThreadPerTaskExecutor</code> executor mitigates trouble mentioned under <a target="_blank" href="https://cljdoc.org/d/funcool/promesa/8.0.450/doc/user-guide#execution-model">Promesa execution model</a>.</p>
<h2 id="heading-introducing-structured-concurrency">Introducing Structured Concurrency</h2>
<p>Structured concurrency is a concurrency programming model described in the following line:</p>
<blockquote>
<p>When a flow of execution splits into multiple concurrent flows, they rejoin in the same code block</p>
</blockquote>
<p>That means we have to be able to bind thread lifetime to a scope. Such scopes should naturally form parent-child relationships and there has to be programming constructs around the hierarchy.</p>
<p>Let's examine this simplistic example:</p>
<pre><code class="lang-clojure">(<span class="hljs-keyword">defn</span> <span class="hljs-title">run-concurrently</span> []
  (<span class="hljs-name"><span class="hljs-builtin-name">let</span></span> [executor (<span class="hljs-name">Executors/newThreadPerTaskExecutor</span> (<span class="hljs-name">thread-factory</span> <span class="hljs-string">"perfectly-scoped-pool-"</span>))]
    (<span class="hljs-name"><span class="hljs-builtin-name">try</span></span> 
      (<span class="hljs-name">.submit</span> executor <span class="hljs-comment">^Callable</span> #(<span class="hljs-name"><span class="hljs-builtin-name">identity</span></span> <span class="hljs-number">2000</span>))
      (<span class="hljs-name">.submit</span> executor <span class="hljs-comment">^Callable</span> #(<span class="hljs-name"><span class="hljs-builtin-name">prn</span></span> <span class="hljs-string">"Starting a long running operation"</span>))
      (<span class="hljs-name">.submit</span> executor <span class="hljs-comment">^Callable</span> #(<span class="hljs-name">Thread/sleep</span> <span class="hljs-number">1000</span>))
      (<span class="hljs-name">.submit</span> executor <span class="hljs-comment">^Callable</span> #(<span class="hljs-name"><span class="hljs-builtin-name">prn</span></span> <span class="hljs-string">"Done."</span>))
      <span class="hljs-number">4</span>
      (<span class="hljs-name">finally</span> (<span class="hljs-name">.close</span> executor)))))

(<span class="hljs-name">run-concurrently</span>)
</code></pre>
<p>Here scope is a function with defined executor against which tasks are submitted. None of the Virtual Threads outlives the scope of the function. Reason being <code>ThreadPerTaskExecutor.close</code> method do the join of the threads and cleanup after them. Caller does not need to know anything about level of concurrency of such method. Also this composes recursively (parent-child relationship), as other functions following the same structure can be called inside the body. It's deterministic and transparent.</p>
<h2 id="heading-avoids">Avoids</h2>
<p>These are less relevant to Clojure developers as most of us do not work on low-level mode of operation, but I'd like to mention them anyway.</p>
<ol>
<li>Avoid <code>ThreadLocal</code> and <code>InheritableThreadLocal</code>. They are supported, but they defeat the cost advantages that come with Virtual Threads</li>
<li>Avoid <code>synchronized</code> methods. Use <code>java.util.concurrent.locks.ReentrantLock</code> instead</li>
<li>Avoid thread pools to control access to expensive resources. Use <code>java.util.concurrent.Semaphore</code> instead</li>
</ol>
<p>Clojure itself <a target="_blank" href="https://github.com/clojure/clojure/search?q=ThreadLocal">contains very few instances of <code>ThreadLocal</code></a>:</p>
<ul>
<li><code>Agent.java</code></li>
<li><code>LockingTransaction.java</code> </li>
<li><code>Var.java</code></li>
<li><code>Instant.clj</code></li>
</ul>
<p>Are they a problem? Probably not. My personal recommendation is to use structured concurrency approach similar to <code>run-concurrently</code> above so that Virtual Threads not live long and unused resources are garbage collected as soon as possible. </p>
<p>At some point JDK can also receive <a target="_blank" href="https://openjdk.java.net/jeps/8263012">Scoped Variables</a> that can be a substitute for expensive ThreadLocals. But it's song of the distant future.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<ul>
<li><code>Virtual Threads</code> are important and extremely useful addition to Java platform</li>
<li>Clojure concurrency mechanisms can be setup and effectively use <code>Virtual Threads</code> today! No modifications to Clojure codebase appears to be necessary</li>
<li>Structured concurrency becomes more important mechanism to deal with concurrent processes once <code>Virtual Threads</code> will be released</li>
<li>Not everything is set to stone. Some mechanisms maybe revisited or adjusted</li>
</ul>
<p>I hope this article triggered intelectual curiosity and provided with interesting information.</p>
<h2 id="heading-references">References</h2>
<ol>
<li><a target="_blank" href="https://www.youtube.com/watch?v=6dpHdo-UnCg&amp;t=474s">YouTube - Practical Advice</a></li>
<li><a target="_blank" href="https://www.youtube.com/watch?v=r6P0_FDr53Q">Ron Pressler - Loom: Bringing Lightweight Threads and Delimited Continuations to the JVM</a></li>
<li><a target="_blank" href="https://openjdk.java.net/jeps/425">JEP 425</a></li>
<li><a target="_blank" href="https://twitter.com/denis_makogon/status/1516112887978283013?s=20&amp;t=Wdwp4Rtsu4VgDNXdO5e21w">Twitter thread on JEP 425</a></li>
<li><a target="_blank" href="https://github.com/openjdk/jdk/commit/9583e3657e43cc1c6f2101a64534564db2a9bd84">Github commit - JDK19 Virtual Threads</a></li>
</ol>
]]></content:encoded></item></channel></rss>