<?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[Sandipsinh Rathod]]></title><description><![CDATA[I post.. sometimes]]></description><link>https://blog.ssdd.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 12 May 2026 10:15:47 GMT</lastBuildDate><atom:link href="https://blog.ssdd.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Taming Dependency Hell in Async Rust]]></title><description><![CDATA[Building a Task Orchestration Engine
Too many times I’ve seen workflows fail because tasks ran in the wrong order, database migrations kicking in before the schema check, services booting before the database was ready, or build steps firing out of se...]]></description><link>https://blog.ssdd.dev/taming-dependency-hell-in-async-rust</link><guid isPermaLink="true">https://blog.ssdd.dev/taming-dependency-hell-in-async-rust</guid><category><![CDATA[software development]]></category><category><![CDATA[architecture]]></category><category><![CDATA[Rust]]></category><category><![CDATA[datastructure]]></category><category><![CDATA[DSA]]></category><dc:creator><![CDATA[Sandipsinh Rathod]]></dc:creator><pubDate>Mon, 29 Sep 2025 06:13:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1759124979406/952c342f-2b1d-479d-a367-75419e274a09.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-building-a-task-orchestration-engine">Building a Task Orchestration Engine</h2>
<p>Too many times I’ve seen workflows fail because tasks ran in the wrong order, database migrations kicking in before the schema check, services booting before the database was ready, or build steps firing out of sequence. These aren’t just deployment headaches; they’re symptoms of a more general problem: coordinating dependent tasks efficiently.</p>
<p>I wanted a clean, reusable way to declare dependencies once and let the runtime figure out the rest. Surprisingly, Rust didn’t have a general-purpose library for this. So I built one: <code>when2task</code>, a dependency-aware task executor for async Rust.</p>
<h3 id="heading-the-problem-space">The Problem Space</h3>
<p>Most systems have tasks that depend on other tasks. Some examples:</p>
<ul>
<li><p><strong>Build systems</strong>: Compile <code>utils</code> before <code>core</code>, compile <code>core</code> before <code>app</code></p>
</li>
<li><p><strong>Deployment scripts</strong>: Start database before API server, start auth service before web frontend</p>
</li>
<li><p><strong>Data pipelines</strong>: Extract data, then validate, then transform, then load</p>
</li>
</ul>
<p>The naive solution is to run everything sequentially:</p>
<pre><code class="lang-rust">Sequential (<span class="hljs-number">8</span> min)
A(<span class="hljs-number">2</span>m) → B(<span class="hljs-number">3</span>m) → C(<span class="hljs-number">1</span>m) → D(<span class="hljs-number">2</span>m)
</code></pre>
<p>But if Task A and B are independent, we're wasting time. The optimal approach requires coordination:</p>
<pre><code class="lang-rust">Optimal (<span class="hljs-number">6</span> min)
 A(<span class="hljs-number">2</span>m) ─┐
        ├─&gt; C(<span class="hljs-number">1</span>m) → D(<span class="hljs-number">2</span>m)
 B(<span class="hljs-number">3</span>m) ─┘
</code></pre>
<h3 id="heading-why-existing-solutions-dont-work">Why Existing Solutions Don't Work</h3>
<p>Other ecosystems solve this with build systems or orchestration frameworks, but in Rust you’d usually end up hand-rolling a DAG (Directed Acyclic Graph) executor. I wanted something different: lightweight, async-native, ergonomic, no config files, no boilerplate, just a clean way to declare dependencies and run tasks.</p>
<p>That meant four things:</p>
<ul>
<li><p>Declare dependencies once, get optimal execution</p>
</li>
<li><p>Zero configuration</p>
</li>
<li><p>Work with async Rust code</p>
</li>
<li><p>Catch dependency cycles at compile time</p>
</li>
</ul>
<h3 id="heading-the-when2task-approach">The when2task Approach</h3>
<p>The core insight is that task scheduling with dependencies is just topological sorting. You build a DAG of tasks, then execute them in topological order with maximum parallelization.</p>
<h4 id="heading-basic-usage">Basic Usage</h4>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> when2task::{ExecutionMode, Task, TaskExecutor};
<span class="hljs-keyword">use</span> std::time::Duration;

<span class="hljs-comment">// Small helper: create the async work future once,</span>
<span class="hljs-comment">// reuse it for independent and dependent tasks.</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">work</span></span>(
    start_msg: &amp;<span class="hljs-symbol">'static</span> <span class="hljs-built_in">str</span>,
    secs: <span class="hljs-built_in">u64</span>,
    done_msg: &amp;<span class="hljs-symbol">'static</span> <span class="hljs-built_in">str</span>,
    ok: &amp;<span class="hljs-symbol">'static</span> <span class="hljs-built_in">str</span>,
) -&gt; <span class="hljs-keyword">impl</span> Future&lt;Output = <span class="hljs-built_in">Result</span>&lt;&amp;<span class="hljs-symbol">'static</span> <span class="hljs-built_in">str</span>, &amp;<span class="hljs-symbol">'static</span> <span class="hljs-built_in">str</span>&gt;&gt; {
    <span class="hljs-keyword">async</span> <span class="hljs-keyword">move</span> {
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{start_msg}"</span>);
        tokio::time::sleep(Duration::from_secs(secs)).<span class="hljs-keyword">await</span>;
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{done_msg}"</span>);
        Ok::&lt;_, &amp;<span class="hljs-built_in">str</span>&gt;(ok)
    }
}

<span class="hljs-meta">#[tokio::main]</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() -&gt; <span class="hljs-built_in">Result</span>&lt;(), <span class="hljs-built_in">Box</span>&lt;<span class="hljs-keyword">dyn</span> std::error::Error&gt;&gt; {
    <span class="hljs-comment">// Independent tasks</span>
    <span class="hljs-keyword">let</span> setup_db = Task::new_independent(work(
        <span class="hljs-string">"Setting up database..."</span>,
        <span class="hljs-number">2</span>,
        <span class="hljs-string">"Database ready"</span>,
        <span class="hljs-string">"db_ready"</span>,
    ));

    <span class="hljs-keyword">let</span> download_assets = Task::new_independent(work(
        <span class="hljs-string">"Downloading assets..."</span>,
        <span class="hljs-number">3</span>,
        <span class="hljs-string">"Assets ready"</span>,
        <span class="hljs-string">"assets_ready"</span>,
    ));

    <span class="hljs-comment">// Dependent tasks</span>
    <span class="hljs-keyword">let</span> start_server = Task::new(
        work(<span class="hljs-string">"Starting server..."</span>, <span class="hljs-number">1</span>, <span class="hljs-string">"Server ready"</span>, <span class="hljs-string">"server_ready"</span>),
        *setup_db.id(), <span class="hljs-comment">// depends on DB only</span>
    );

    <span class="hljs-keyword">let</span> run_tests = Task::new(
        work(<span class="hljs-string">"Running tests..."</span>, <span class="hljs-number">2</span>, <span class="hljs-string">"Tests complete"</span>, <span class="hljs-string">"tests_done"</span>),
        [*start_server.id(), *download_assets.id()], <span class="hljs-comment">// depends on both</span>
    );

    <span class="hljs-keyword">let</span> result = TaskExecutor::new(ExecutionMode::true_async())
        .insert(setup_db)
        .insert(download_assets)
        .insert(start_server)
        .insert(run_tests)
        .execute()
        .<span class="hljs-keyword">await</span>?;

    <span class="hljs-built_in">println!</span>(
        <span class="hljs-string">"Completed {}/{} tasks"</span>,
        result.successful_tasks, result.total_tasks
    );
    <span class="hljs-literal">Ok</span>(())
}
</code></pre>
<p>Note that the example code might not be up to date with the dependency, refer the dependency’s README at <a target="_blank" href="https://crates.io/crates/when2task">https://crates.io/crates/when2task</a> for latest code.</p>
<h4 id="heading-execution-flow">Execution Flow</h4>
<p>The library automatically figures out the optimal execution plan:</p>
<pre><code class="lang-plaintext">Step 1: [setup_db, download_assets] run in parallel (3 seconds)
Step 2: [start_server] runs after setup_db (1 second)
Step 3: [run_tests] runs after both start_server and download_assets (2 seconds)

Total: 6 seconds instead of 8 sequential
</code></pre>
<h3 id="heading-error-handling">Error Handling</h3>
<p>The library distinguishes between setup errors and runtime errors:</p>
<pre><code class="lang-rust"><span class="hljs-keyword">match</span> executor.execute().<span class="hljs-keyword">await</span> {
    <span class="hljs-literal">Ok</span>(result) =&gt; {
        <span class="hljs-keyword">if</span> result.has_failures() {
            <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Some tasks failed:"</span>);
            <span class="hljs-keyword">for</span> failed <span class="hljs-keyword">in</span> result.failed_results() {
                <span class="hljs-built_in">println!</span>(<span class="hljs-string">"  {} failed: {:?}"</span>, failed.task_id, failed.result);
            }
        }
    }
    <span class="hljs-literal">Err</span>(when2task::ExecutionError::BlueprintError(
        when2task::BlueprintError::CircularDependency(cycle)
    )) =&gt; {
        eprintln!(<span class="hljs-string">"Circular dependency detected: {:?}"</span>, cycle);
        <span class="hljs-comment">// This is caught at setup time, not runtime</span>
    }
    <span class="hljs-literal">Err</span>(e) =&gt; eprintln!(<span class="hljs-string">"Execution failed: {}"</span>, e),
}
</code></pre>
<h3 id="heading-design-decisions">Design Decisions</h3>
<h4 id="heading-why-topological-sorting">Why Topological Sorting?</h4>
<p>It's the proven algorithm for dependency resolution. Every build system uses some variant of this. The innovation isn't the algorithm - it's the ergonomic API and async integration.</p>
<h4 id="heading-execution-modes">Execution Modes</h4>
<p>For now, the library supports two execution modes:</p>
<pre><code class="lang-rust"><span class="hljs-comment">// Direct execution - tasks run on the current runtime</span>
TaskExecutor::new(ExecutionMode::true_async())

<span class="hljs-comment">// Spawned execution - tasks run on separate spawned tasks</span>
TaskExecutor::new(ExecutionMode::pseudo_async(tokio::spawn))
</code></pre>
<p>Use spawned execution if you need task isolation or cancellation support.</p>
<h3 id="heading-performance-characteristics">Performance Characteristics</h3>
<ul>
<li><p><strong>Setup</strong>: O(V + E) to build the execution plan (V = tasks, E = dependencies)</p>
</li>
<li><p><strong>Memory</strong>: O(V) for task storage, plus whatever your tasks allocate</p>
</li>
<li><p><strong>Execution</strong>: Bounded by the critical path, not total task count</p>
</li>
</ul>
<p>For typical workloads, the library overhead is negligible compared to actual task execution time.</p>
<h3 id="heading-when-to-use-this">When to Use This</h3>
<p><strong>Good fit:</strong></p>
<ul>
<li><p>You have tasks with dependencies that could run in parallel</p>
</li>
<li><p>You want optimal execution without manual coordination</p>
</li>
</ul>
<p><strong>Not a good fit:</strong></p>
<ul>
<li><p>Tasks have no dependencies (just use <code>tokio::try_join!</code>)</p>
</li>
<li><p>You want dynamic dependency discovery at runtime</p>
</li>
</ul>
<h3 id="heading-ps">PS</h3>
<p>Building <code>when2task</code> was refreshing. It turned chaotic workflows into something orderly. For me, the fun wasn’t just solving the problem, but shaping the solution: the three-level design, the architecture, and the API all reflect the programming taste I’ve been refining over the years.</p>
<h3 id="heading-sources-code">Sources code</h3>
<p>The source code is on <a target="_blank" href="https://github.com/ssddOnTop/when2task">GitHub</a> and the crate is on <a target="_blank" href="https://crates.io/crates/when2task">crates.io</a>. MIT licensed, because coordination should be free.</p>
<hr />
<p><em>Written by a developer who got tired of tasks running in the wrong order.</em></p>
]]></content:encoded></item><item><title><![CDATA[Boost JSON Lines Processing with a High-Performance Rust Library]]></title><description><![CDATA[As a developer working with large datasets, I've often found myself wrestling with JSON Lines (JSONL) files. Whether it's processing log files, handling data exports, or working with streaming APIs, JSONL has become ubiquitous in the data world. Howe...]]></description><link>https://blog.ssdd.dev/building-async-jsonl</link><guid isPermaLink="true">https://blog.ssdd.dev/building-async-jsonl</guid><category><![CDATA[jsonl]]></category><category><![CDATA[Rust]]></category><category><![CDATA[asynchronous]]></category><category><![CDATA[tokio]]></category><category><![CDATA[data processing]]></category><dc:creator><![CDATA[Sandipsinh Rathod]]></dc:creator><pubDate>Wed, 04 Jun 2025 18:05:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1749060194906/933f0c6a-4475-4368-ad1b-8e21ce27d861.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As a developer working with large datasets, I've often found myself wrestling with JSON Lines (JSONL) files. Whether it's processing log files, handling data exports, or working with streaming APIs, JSONL has become ubiquitous in the data world. However, I noticed a gap in the Rust ecosystem for efficient, async-first JSONL processing. That's why I decided to create <strong>async-jsonl</strong> - and I'm excited to share what I've built!</p>
<h2 id="heading-what-is-json-lines-jsonl">What is JSON Lines (JSONL)?</h2>
<p>Before diving into my library, let's quickly cover what JSONL actually is. JSON Lines is a text format where each line is a valid JSON object, separated by newline characters. It looks like this:</p>
<pre><code class="lang-json">{<span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Alice"</span>, <span class="hljs-attr">"age"</span>: <span class="hljs-number">30</span>}
{<span class="hljs-attr">"id"</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Bob"</span>, <span class="hljs-attr">"age"</span>: <span class="hljs-number">25</span>}
{<span class="hljs-attr">"id"</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Charlie"</span>, <span class="hljs-attr">"age"</span>: <span class="hljs-number">35</span>}
</code></pre>
<h3 id="heading-why-jsonl-is-awesome">Why JSONL is Awesome</h3>
<ol>
<li><p><strong>Streamable</strong>: You can process one line at a time without loading the entire file into memory</p>
</li>
<li><p><strong>Appendable</strong>: Easy to add new records to the end of a file</p>
</li>
<li><p><strong>Fault-tolerant</strong>: One corrupted line doesn't break the entire dataset</p>
</li>
<li><p><strong>Tool-friendly</strong>: Works great with unix tools like <code>cat</code>, <code>head</code>, <code>tail</code>, and <code>grep</code></p>
</li>
<li><p><strong>Language-agnostic</strong>: Supported across virtually every programming language</p>
</li>
</ol>
<p>These advantages make JSONL perfect for log files, data pipelines, and any scenario where you're dealing with large volumes of structured data.</p>
<h2 id="heading-enter-async-jsonl-built-for-performance-and-simplicity">Enter async-jsonl: Built for Performance and Simplicity</h2>
<p>While working on various Rust projects that needed to process large JSONL files, I kept running into the same issues:</p>
<ul>
<li><p>Existing solutions weren't async-first</p>
</li>
<li><p>Memory usage would explode with large files</p>
</li>
<li><p>Error handling was either too strict (one bad line kills everything) or too loose</p>
</li>
<li><p>Type safety was often sacrificed for convenience</p>
</li>
</ul>
<p>So I built <strong>async-jsonl</strong> to solve these problems. Here's what makes it special:</p>
<h3 id="heading-asyncawait-from-the-ground-up">🚀 <strong>Async/Await from the Ground Up</strong></h3>
<p>Built on Tokio, async-jsonl is designed for high-performance async I/O. <strong>No blocking</strong> the event loop here!</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> async_jsonl::Jsonl;
<span class="hljs-keyword">use</span> futures::StreamExt;

<span class="hljs-meta">#[tokio::main]</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() -&gt; anyhow::<span class="hljs-built_in">Result</span>&lt;()&gt; {
    <span class="hljs-keyword">let</span> jsonl = Jsonl::from_path(<span class="hljs-string">"data.jsonl"</span>).<span class="hljs-keyword">await</span>?;

    <span class="hljs-keyword">let</span> lines: <span class="hljs-built_in">Vec</span>&lt;_&gt; = jsonl.collect().<span class="hljs-keyword">await</span>;
    <span class="hljs-keyword">for</span> line_result <span class="hljs-keyword">in</span> lines {
        <span class="hljs-keyword">let</span> line = line_result?;
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Raw JSON: {}"</span>, line);
    }

    <span class="hljs-literal">Ok</span>(())
}
</code></pre>
<h3 id="heading-memory-efficient-streaming">💾 <strong>Memory Efficient Streaming</strong></h3>
<p>Process files of any size without loading everything into memory. The streaming approach means you can handle gigabyte files with minimal RAM usage.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> async_jsonl::{Jsonl, JsonlDeserialize};
<span class="hljs-keyword">use</span> futures::StreamExt;
<span class="hljs-keyword">use</span> serde::Deserialize;

<span class="hljs-meta">#[derive(Debug, Deserialize)]</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">LogEntry</span></span> {
    timestamp: <span class="hljs-built_in">String</span>,
    level: <span class="hljs-built_in">String</span>,
    message: <span class="hljs-built_in">String</span>,
}

<span class="hljs-meta">#[tokio::main]</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() -&gt; anyhow::<span class="hljs-built_in">Result</span>&lt;()&gt; {
    <span class="hljs-keyword">let</span> jsonl = Jsonl::from_path(<span class="hljs-string">"huge_log_file.jsonl"</span>).<span class="hljs-keyword">await</span>?;
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> stream = jsonl.deserialize::&lt;LogEntry&gt;();

    <span class="hljs-comment">// Process one record at a time - O(1) memory usage!</span>
    <span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(entry_result) = stream.next().<span class="hljs-keyword">await</span> {
        <span class="hljs-keyword">let</span> entry = entry_result?;
        <span class="hljs-keyword">if</span> entry.level == <span class="hljs-string">"ERROR"</span> {
            <span class="hljs-built_in">println!</span>(<span class="hljs-string">"🚨 Error at {}: {}"</span>, entry.timestamp, entry.message);
        }
    }

    <span class="hljs-literal">Ok</span>(())
}
</code></pre>
<h3 id="heading-type-safe-with-serde-integration">🔒 <strong>Type-Safe with Serde Integration</strong></h3>
<p>Full integration with serde means you get compile-time type checking and zero-cost deserialization.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> async_jsonl::{Jsonl, JsonlDeserialize};
<span class="hljs-keyword">use</span> futures::StreamExt;
<span class="hljs-keyword">use</span> serde::Deserialize;

<span class="hljs-meta">#[derive(Debug, Deserialize)]</span>
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">User</span></span> {
    id: <span class="hljs-built_in">u64</span>,
    name: <span class="hljs-built_in">String</span>,
    email: <span class="hljs-built_in">String</span>,
    <span class="hljs-meta">#[serde(default)]</span>
    is_verified: <span class="hljs-built_in">bool</span>,
}

<span class="hljs-meta">#[tokio::main]</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() -&gt; anyhow::<span class="hljs-built_in">Result</span>&lt;()&gt; {
    <span class="hljs-keyword">let</span> jsonl = Jsonl::from_path(<span class="hljs-string">"users.jsonl"</span>).<span class="hljs-keyword">await</span>?;
    <span class="hljs-keyword">let</span> users = jsonl.deserialize::&lt;User&gt;();

    <span class="hljs-keyword">let</span> results: <span class="hljs-built_in">Vec</span>&lt;_&gt; = users.collect().<span class="hljs-keyword">await</span>;
    <span class="hljs-keyword">for</span> user_result <span class="hljs-keyword">in</span> results {
        <span class="hljs-keyword">let</span> user = user_result?;
        <span class="hljs-built_in">println!</span>(<span class="hljs-string">"{:?}"</span>, user);
    }

    <span class="hljs-literal">Ok</span>(())
}
</code></pre>
<h3 id="heading-resilient-error-handling">🛡️ <strong>Resilient Error Handling</strong></h3>
<p>One of my favorite features: the library continues processing even when individual lines fail to parse. Perfect for real-world data that's not always perfect.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> async_jsonl::{Jsonl, JsonlValueDeserialize};
<span class="hljs-keyword">use</span> futures::StreamExt;

<span class="hljs-meta">#[tokio::main]</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() -&gt; anyhow::<span class="hljs-built_in">Result</span>&lt;()&gt; {
    <span class="hljs-keyword">let</span> jsonl = Jsonl::from_path(<span class="hljs-string">"messy_data.jsonl"</span>).<span class="hljs-keyword">await</span>?;
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> stream = jsonl.deserialize_values();

    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> valid_records = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">let</span> <span class="hljs-keyword">mut</span> error_count = <span class="hljs-number">0</span>;

    <span class="hljs-keyword">while</span> <span class="hljs-keyword">let</span> <span class="hljs-literal">Some</span>(result) = stream.next().<span class="hljs-keyword">await</span> {
        <span class="hljs-keyword">match</span> result {
            <span class="hljs-literal">Ok</span>(value) =&gt; {
                valid_records += <span class="hljs-number">1</span>;
                <span class="hljs-comment">// Process valid JSON</span>
                <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Valid record: {}"</span>, value);
            }
            <span class="hljs-literal">Err</span>(e) =&gt; {
                error_count += <span class="hljs-number">1</span>;
                eprintln!(<span class="hljs-string">"Skipping invalid line: {}"</span>, e);
                <span class="hljs-comment">// Keep going!</span>
            }
        }
    }

    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"Processed {} valid records, {} errors"</span>, valid_records, error_count);
    <span class="hljs-literal">Ok</span>(())
}
</code></pre>
<h3 id="heading-flexible-input-sources">📖 <strong>Flexible Input Sources</strong></h3>
<p>Whether you're reading from files, memory, or any <code>AsyncRead</code> source, async-jsonl has you covered.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> async_jsonl::Jsonl;
<span class="hljs-keyword">use</span> std::io::Cursor;

<span class="hljs-meta">#[tokio::main]</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() -&gt; anyhow::<span class="hljs-built_in">Result</span>&lt;()&gt; {
    <span class="hljs-keyword">let</span> data = <span class="hljs-string">r#"{"id": 1, "name": "Alice"}
{"id": 2, "name": "Bob"}
{"id": 3, "name": "Charlie"}
"#</span>;

    <span class="hljs-comment">// Read from memory</span>
    <span class="hljs-keyword">let</span> reader = Cursor::new(data.as_bytes());
    <span class="hljs-keyword">let</span> jsonl = Jsonl::new(reader);

    <span class="hljs-comment">// Or read from a file</span>
    <span class="hljs-keyword">let</span> file_jsonl = Jsonl::from_path(<span class="hljs-string">"data.jsonl"</span>).<span class="hljs-keyword">await</span>?;

    <span class="hljs-literal">Ok</span>(())
}
</code></pre>
<h3 id="heading-advanced-features-for-power-users">🎯 <strong>Advanced Features for Power Users</strong></h3>
<p>The library also includes some advanced features I found myself needing repeatedly:</p>
<p><strong>Line Counting Without Full Processing:</strong></p>
<pre><code class="lang-rust"><span class="hljs-keyword">use</span> async_jsonl::{Jsonl, JsonlReader};

<span class="hljs-meta">#[tokio::main]</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">main</span></span>() -&gt; anyhow::<span class="hljs-built_in">Result</span>&lt;()&gt; {
    <span class="hljs-keyword">let</span> jsonl = Jsonl::from_path(<span class="hljs-string">"massive_file.jsonl"</span>).<span class="hljs-keyword">await</span>?;
    <span class="hljs-keyword">let</span> count = jsonl.count().<span class="hljs-keyword">await</span>?;

    <span class="hljs-built_in">println!</span>(<span class="hljs-string">"File contains {} records"</span>, count);
    <span class="hljs-literal">Ok</span>(())
}
</code></pre>
<h2 id="heading-the-technical-journey">The Technical Journey</h2>
<p>Building this library taught me a lot about async Rust and streaming APIs. Some key decisions I made:</p>
<ol>
<li><p><strong>Tokio as the Foundation</strong>: Built on <code>tokio::io</code> for maximum compatibility with the async ecosystem</p>
</li>
<li><p><strong>Stream-based Architecture</strong>: Using futures's <code>Stream</code> trait for composable, lazy processing</p>
</li>
<li><p><strong>Zero-copy Where Possible</strong>: Minimizing allocations while maintaining safety</p>
</li>
<li><p><strong>Comprehensive Error Types</strong>: Using <code>anyhow</code> for ergonomic error handling without sacrificing information</p>
</li>
</ol>
<h2 id="heading-real-world-performance">Real-World Performance</h2>
<p>In my testing with large datasets (&gt;1GB JSONL files), async-jsonl consistently shows:</p>
<ul>
<li><p><strong>Memory usage</strong>: Constant regardless of file size</p>
</li>
<li><p><strong>Throughput</strong>: Competitive with the fastest JSONL parsers in any language</p>
</li>
<li><p><strong>CPU efficiency</strong>: Low overhead thanks to Rust's zero-cost abstractions</p>
</li>
</ul>
<h2 id="heading-try-it-yourself">Try It Yourself!</h2>
<p>The library is available on <a target="_blank" href="https://crates.io/crates/async-jsonl">crates.io</a> and the source is on <a target="_blank" href="https://github.com/gpmcp/async-jsonl">GitHub</a>. Here's how to get started:</p>
<pre><code class="lang-ini"><span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">async-jsonl</span> = <span class="hljs-string">"0.3.1"</span>
<span class="hljs-attr">tokio</span> = { version = <span class="hljs-string">"1.0"</span>, features = [<span class="hljs-string">"full"</span>] }
<span class="hljs-attr">futures</span> = <span class="hljs-string">"0.3"</span>
<span class="hljs-attr">serde</span> = { version = <span class="hljs-string">"1.0"</span>, features = [<span class="hljs-string">"derive"</span>] }
<span class="hljs-attr">anyhow</span> = <span class="hljs-string">"1.0"</span>
</code></pre>
<p>I'd love to hear how you use it in your projects! Whether you're processing logs, handling data pipelines, or working with APIs, async-jsonl is designed to make your life easier.</p>
<hr />
<p><em>What do you think? Have you worked with JSONL files before? What features would you find most useful in a JSONL processing library? Let me know in the comments below!</em></p>
]]></content:encoded></item><item><title><![CDATA[How I won $2k hackathon (Rust)]]></title><description><![CDATA[Who am I?
I am Sandipsinh Rathod, a 2nd year student at Nirma University pursuing Bachelor's degree in Computer Science.
What is Rust?
Rust is a fairly new programming language, first stable version was released in May 2015. It is rapidly gaining pop...]]></description><link>https://blog.ssdd.dev/how-i-won-2k-hackathon-rust</link><guid isPermaLink="true">https://blog.ssdd.dev/how-i-won-2k-hackathon-rust</guid><category><![CDATA[Rust]]></category><category><![CDATA[hacktoberfest]]></category><category><![CDATA[tailcall]]></category><dc:creator><![CDATA[Sandipsinh Rathod]]></dc:creator><pubDate>Thu, 04 Apr 2024 14:52:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1712239400631/648d58d4-3f24-44ae-a67d-c1379e278468.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-who-am-i">Who am I?</h3>
<p>I am Sandipsinh Rathod, a 2nd year student at <a target="_blank" href="https://nirmauni.ac.in/">Nirma University</a> pursuing Bachelor's degree in Computer Science.</p>
<h3 id="heading-what-is-rust">What is Rust?</h3>
<p><a target="_blank" href="https://www.rust-lang.org">Rust</a> is a fairly new programming language, first stable version was released in May 2015. It is rapidly gaining popularity and it's been <a target="_blank" href="https://survey.stackoverflow.co/2023/#section-admired-and-desired-programming-scripting-and-markup-languages">most admired language for 8 years in a row</a>.</p>
<h3 id="heading-how-i-feel-about-rust">How I feel about Rust</h3>
<p>I have been practicing Rust since 2021, the learning curve for Rust is indeed quite steep but I can say that it's all worth it. Rust forces to "unlearn" terrible practices that you might have learn from other languages and it forces you to write some better code! Yes, Rust requires a lot of practice, which may lead you to lose friends; but hey you will definitely have Rust's compiler as your new friend!</p>
<h3 id="heading-the-contribution-and-hackathon-phase">The contribution and hackathon phase</h3>
<p>I never focused on money and I just like exploring stuff.. Past year, in Oct. 2023, I was looking for some repository to contribute for <a target="_blank" href="https://hacktoberfest.com/">hacktoberfest</a> and I stumbled upon this awesome repository called <a target="_blank" href="https://tailcall.run/">Tailcall</a>. It not only had a lot of issues open but also bounties on it! Which means that I can actually earn while contributing to the repo. Win-win situation right?</p>
<p>My first contribution to Tailcall was to bring HTTP support for reading configuration files (<a target="_blank" href="https://github.com/tailcallhq/tailcall/pull/609">#609</a>) where I made my first ~$150 in open-source contributions.</p>
<p>Then a few months passed by and I had been contributing to Tailcall all that time, and I got a big opportunity, where Tailcall hosted a mini hackathon to bring WASM compatibility to the project with MASSIVE $2000 bounty on it (<a target="_blank" href="https://github.com/tailcallhq/tailcall/issues/750">#750</a>). Bringing WASM compatibility to a CLI application was huge challenge, it took me 3 days to make my first working PR (Pull Request) which make Tailcall compatible with <a target="_blank" href="https://workers.cloudflare.com/">Cloudflare Workers</a> (i.e. WASM compatible).</p>
<p>Of course, 3 days of work wasn't enough, the code worked but it was huge mess. Luckily, at that period of time, my university announced that my batch had to do mandatory internship in upcoming weeks, and of course, I applied to Tailcall and they happily accepted me as their intern for upcoming month. I started my internship at Tailcall under <a target="_blank" href="https://www.linkedin.com/in/tusharmath">Tushar Mathur</a> (Ex VPE <a target="_blank" href="https://www.dream11.com/">@Dream11</a>) and <a target="_blank" href="https://in.linkedin.com/in/amitksingh1490">Amit Singh</a>. In the internship, basically my task was to cleanup the code and grab the bounty :p</p>
<p>After a month of hard work and 20+ PRs, I was finally awarded the bounty on 3rd Feb, 2024.</p>
<h3 id="heading-what-did-i-learn-during-internship">What did I learn during internship?</h3>
<p>Well, this is more important section in my opinion. Before any contributions, I was just a "programmer" who can just get the job done, but the code quality might not be great etc etc...</p>
<p>After the completion of internship, I can proudly say that I became a software engineer. The team at tailcall is quite supportive, especially Tushar, being a great leader, supported me throughout the duration of internship. I can say that Tushar played an important role in upgrading my skills.</p>
<p>I always like exploring stuff and I really wanted to explore GraphQL and GRPC for a long period of time, but I always procrastinated. I can say that bounties were huge motivation for me to explore them and now I can say that I have fairly good knowledge about both of them.</p>
<h3 id="heading-the-story-still-continues">The story still continues</h3>
<p><a target="_blank" href="https://console.algora.io/">algora.io</a> is a platform which allows people to put bounties on the github issues and allows contributors to claim 100% of the amount upon completion of the issue.</p>
<p>Tailcall uses the same platform. After taking some break I started contributing to the same repository again. Sticking to same repository helps in gaining deep understanding of the code-base. Now I am able to solve majority of the issues which are published at Tailcall. I never tried to contribute to any other repo, provided that financial gain isn't my first goal.</p>
<p>However by contributing to just to single repository, I am currently ranked #7 on algora.io <a target="_blank" href="https://console.algora.io/leaderboard">leader board</a> by making over $5000 in bounties, in 2 months.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>I am not paid by any of the platforms which I mentioned in this blog, this blog is purely based on my personal experience in past few months.</p>
<p>I hope you learnt something new and interesting from this blog. Happy contributing!</p>
]]></content:encoded></item></channel></rss>