<?xml version="1.0" encoding="utf-8"?>
  <rss version="2.0">
    <channel>
      <title>krausshalt</title>
      <link>https://krausshalt.com</link>
      <description>krausshalt.com - Max' personal portfolio</description>
      <language>en-US</language>
      <item>
    <title>Scheduled jobs in kubernetes</title>
    <description>
      <![CDATA[
        <p>Sometimes it's necessary  to have work done not on demand (i.e. with a web service reacting to requests) but rather on a schedule.</p>
<p>What first came to my mind was a constantly running service which does the same as cron is doing on *nix systems. But since we are using kubernetes as our container orchestrator I thought they may be have something in place for my use case, and in fact they do!</p>
<p>In kubernetes world this feature is called "CronJob" and it behaves exactly like the UNIX counterpart.</p>
<p>Boiled down to the basics it's just:</p>
<ul>
<li>a Name</li>
<li>a cron schedule string (I'm always using <a href="https://crontab.guru/">https://crontab.guru/</a> to make sure I'm doing it right)</li>
<li>a Docker image</li>
<li>a command (or list of commands) what to do</li>
</ul>
<p>The only thing to consider is what should happen if the schedule triggers but the execution from the previous run is not yet completed. kubernetes offers you three options known as concurrency policies from which you can choose:</p>
<ul>
<li><code>Allow (default)</code>: The cron job allows concurrently running jobs</li>
<li><code>Forbid</code>: The cron job does not allow concurrent runs; if it is time for a new job run and the previous job run hasn’t finished yet, the cron job skips the new job run</li>
<li><code>Replace</code>: If it is time for a new job run and the previous job run hasn’t finished yet, the cron job replaces the currently running job run with a new job run
Source: <a href="https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/">https://kubernetes.io/docs/tasks/job/automated-tasks-with-cron-jobs/</a></li>
</ul>
<p>And last but not least an example of one of our jobs which runs since months reliable on production:</p>
<pre><code>apiVersion: batch/v1
kind: CronJob
metadata:
  name: job-foo-bar-thing
spec:
  schedule: "*/5 * * * *"
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 1
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: job-foo-bar-thing
            image: {{DOCKER_IMAGE}}
            imagePullPolicy: Always
            env:
              - name: PORT
                value: "80"
              - name: NODE_ENV
                value: {{NODE_ENV}}
              - name: LOG_LEVEL
                value: {{LOG_LEVEL}}

            args:
            - npm
            - start
          restartPolicy: Never
</code></pre>

      ]]>
    </description>
    <link>https://krausshalt.com/notes/scheduled-jobs-in-kubernetes</link>
    <author>Maximilian Krauss</author>
    <guid>scheduled-jobs-in-kubernetes</guid>
    <pubDate>2022-01-07</pubDate>
  </item>,<item>
    <title>Async iterators with mongo DB</title>
    <description>
      <![CDATA[
        <h3>Asynchronous batched iterable for (mongo) cursors. When one is not enough and all is too much</h3>
<p>Async iterators landed fresh in node.js v10 as experimental option and since then they have been evolved to latest LTS and stable versions of node.js</p>
<p>Since then I never had a real use case for them. But recently we had to process a lot of data from mongo db without dumping the whole collection into memory.</p>
<p>First result just uses the regular mongo cursor and a simple <code>for ... each</code> loop to process the data one after the other:</p>
<pre><code>collection.find(...).forEach(document => process(document)
    .then(...) // Does not block, so promises arent possible at all
    .catch(...)
)
</code></pre>
<p>This works but neither supports promises nor is very efficient. Second approach is my very first usage of the new async iterator syntax by just iterating through the cursor:</p>
<pre><code>for await (const document of cursor.find(...)) {
  await process(document)
}
</code></pre>
<p>Surprisingly this just works out of the box because the mongo cursor exposes an asynchronous <code>next()</code> method which is all what's required in order to loop through that collection.
That's one nice solution but has a drawback: What if <code>process(document)</code> needs some time and slows down processing of those documents?</p>
<p>Now I need a batch of documents which could processed in parallel but not all of them a the same time to fuckup memory. To the ...</p>
<h3>Bat(ch) Mobile</h3>
<p>I <a href="https://max.krauss.io/async-iterators-with-mongo-db/#:~:text=I-,wrote,-a%20small%20node">wrote a small node module</a> which does exactly that: Fetching N items from n cursor (does not have to be mongo), yields the batch of items and awaits the processing.  And so on and so on until the cursor is exhausted. The example from above would look like this now:</p>
<pre><code>const { getBatchedIterableFromCursor } = require('batch-mobile')

const cursor = collection.find(...)
for await (const batchOfItems of getBatchedIterableFromCursor(cursor, 100)) {
  await process(batchOfItems) //this is now an array of items
}
</code></pre>
<p>The only change is that the <code>document</code> is now an array of documents and one additional function call where the size of the batch is specified (default is 200).</p>

      ]]>
    </description>
    <link>https://krausshalt.com/notes/async-iterators-with-mongo-db</link>
    <author>Maximilian Krauss</author>
    <guid>async-iterators-with-mongo-db</guid>
    <pubDate>2020-03-04</pubDate>
  </item>
    </channel>
  
  </rss>