<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Okikiola Ashiru</title>
    <description>The latest articles on DEV Community by Okikiola Ashiru (@0xkikiola).</description>
    <link>https://dev.to/0xkikiola</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4052767%2Fec3eb26e-78ed-42ea-9cb1-ef2565712b26.jpg</url>
      <title>DEV Community: Okikiola Ashiru</title>
      <link>https://dev.to/0xkikiola</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/0xkikiola"/>
    <language>en</language>
    <item>
      <title>I Built a Security-Gating CI Pipeline, Then Discovered It Wasn't Actually Gating Anything</title>
      <dc:creator>Okikiola Ashiru</dc:creator>
      <pubDate>Thu, 13 Aug 2026 07:22:22 +0000</pubDate>
      <link>https://dev.to/0xkikiola/i-built-a-security-gating-ci-pipeline-then-discovered-it-wasnt-actually-gating-anything-21m8</link>
      <guid>https://dev.to/0xkikiola/i-built-a-security-gating-ci-pipeline-then-discovered-it-wasnt-actually-gating-anything-21m8</guid>
      <description>&lt;p&gt;A security check that fails but doesn't block a merge isn't a security gate. It's a warning label nobody has to read.&lt;/p&gt;

&lt;p&gt;I learned that the hard way building &lt;strong&gt;pipeline-gatekeeper&lt;/strong&gt;, a small CI/CD pipeline that wires together three open-source security scanners: Trivy for container vulnerabilities, gitleaks for exposed secrets, and Trivy IaC for insecure Terraform configuration. The goal wasn't to build new scanning tools. It was to prove that wiring existing, trusted tools together correctly actually catches what it's supposed to catch, and to find out where "correctly" breaks down in practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;Three parallel jobs run on every pull request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Container Vulnerability Scan (Trivy):&lt;/strong&gt; scans the built Docker image for CRITICAL and HIGH severity CVEs in both OS packages and Python dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret Detection (gitleaks):&lt;/strong&gt; scans the full commit history for hardcoded API keys, tokens, and credentials.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terraform Policy Scan (Trivy IaC, using tfsec rulesets):&lt;/strong&gt; scans Terraform configuration for misconfigurations like unencrypted storage or missing public-access restrictions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Trivy was the natural choice for both container and IaC scanning since it runs as a single stateless binary with no daemon or database, and using one tool for two of the three gates kept the pipeline simpler than adding a separate IaC-specific scanner.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsldtm0ska3reaeo4wcup.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsldtm0ska3reaeo4wcup.jpg" alt="project structure" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Proving it actually works, not just that it's configured
&lt;/h2&gt;

&lt;p&gt;Design decisions are easy to write down and easy to get wrong in practice, so I tested this the same way I've tested every project before it: by deliberately breaking things and watching what happened.&lt;/p&gt;

&lt;p&gt;I opened a pull request with three real violations baked in on purpose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A dependency (&lt;code&gt;pillow==8.2.0&lt;/code&gt;) with a known critical remote-code-execution CVE&lt;/li&gt;
&lt;li&gt;A hardcoded GitHub personal access token, formatted exactly like a real one, in a config file&lt;/li&gt;
&lt;li&gt;An AWS EBS volume in Terraform with &lt;code&gt;encrypted = false&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three checks failed, exactly as expected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx1kz1fi5fv4kl4l5lkzh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx1kz1fi5fv4kl4l5lkzh.png" alt="pr-failing-checks" width="618" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I found when I looked closer
&lt;/h2&gt;

&lt;p&gt;This is the part that actually mattered. Two things went wrong that I hadn't planned for, and both were more useful to find than a clean pass would have been.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First: failing checks didn't actually block the merge.&lt;/strong&gt; GitHub showed all three checks red, and right underneath, it also showed "No conflicts with base branch. Merging can be performed automatically," with an active merge button. The scanners were detecting violations correctly. Nothing was stopping anyone from merging past them anyway. Detection and enforcement turned out to be two completely separate things, and I'd only built the first one. The fix is a branch protection rule requiring these checks to pass before merge, which GitHub Actions doesn't set up for you by default just because a workflow exists.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn2csltx6wcvbhaikq12r.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn2csltx6wcvbhaikq12r.jpg" alt="No conflicts with base branch. Merging can be performed automatically" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second: gitleaks found the secret but couldn't tell me about it where I was looking.&lt;/strong&gt; It tried to post a summary comment directly on the pull request and failed with a permissions error, &lt;code&gt;Resource not accessible by integration&lt;/code&gt;. The scan still worked. It still reported the leak in the job logs and summary. It just couldn't write to the PR itself, because the default &lt;code&gt;GITHUB_TOKEN&lt;/code&gt; didn't have &lt;code&gt;pull-requests: write&lt;/code&gt; permission. An easy fix once I saw it, but exactly the kind of thing that looks fine in a demo and quietly fails in a way you don't notice until you go looking for the comment that should be there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhyfywxy2s7i0v34gf73a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhyfywxy2s7i0v34gf73a.png" alt="gitleaks logs" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I'm glad I found these instead of avoiding them
&lt;/h2&gt;

&lt;p&gt;It would have been easy to stop at "all three checks failed as expected" and call the project done. That's what the first version of my own README said, before I looked closely enough at the actual PR to notice the merge button was still active.&lt;/p&gt;

&lt;p&gt;The gap between "the check fails" and "the merge is blocked" is exactly the kind of thing that's invisible until someone tests it end to end, and it's a real, common misconfiguration, not a contrived edge case. A pipeline that reports failures nobody has to act on isn't protecting anything. It's just generating logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  After fixing both issues
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhfc3kzgtgxlwms60v3ik.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhfc3kzgtgxlwms60v3ik.png" alt="failing checks now genuinely blocking the merge button" width="747" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdpvrp8hfeysrdhvgl4cg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdpvrp8hfeysrdhvgl4cg.png" alt="gitleaks now leaves a full inline review comment directly on the offending line" width="716" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What this project didn't try to be
&lt;/h2&gt;

&lt;p&gt;This isn't a production security platform, and three scanners wired into one workflow isn't a complete security posture. It doesn't cover runtime security, dependency license compliance, or SAST for the application code itself. What it does prove, concretely, is the difference between a pipeline that looks like it's enforcing something and one that actually is, and that difference is worth checking for directly instead of assuming.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Repo: &lt;a href="https://github.com/aashiruu/pipeline-gatekeeper" rel="noopener noreferrer"&gt;github.com/aashiruu/pipeline-gatekeeper&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>security</category>
      <category>devsecops</category>
      <category>docker</category>
    </item>
    <item>
      <title>What Happens When "Secure" and "Available" Disagree? Building a Healthcare Access-Control System Taught Me There's No Clean Answer</title>
      <dc:creator>Okikiola Ashiru</dc:creator>
      <pubDate>Wed, 05 Aug 2026 12:12:41 +0000</pubDate>
      <link>https://dev.to/0xkikiola/what-happens-when-secure-and-available-disagree-building-a-healthcare-access-control-system-1lb6</link>
      <guid>https://dev.to/0xkikiola/what-happens-when-secure-and-available-disagree-building-a-healthcare-access-control-system-1lb6</guid>
      <description>&lt;h2&gt;
  
  
  What Happens When "Secure" and "Available" Disagree? Building a Healthcare Access-Control System Taught Me There's No Clean Answer
&lt;/h2&gt;

&lt;p&gt;Fintech's constraint was correctness, never double-charge someone. Chaos engineering's constraint was recovery, does the system actually heal, not just look healed. Healthcare access control turned out to be a different problem again: &lt;strong&gt;what do you do when being strict and being available point in opposite directions?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's the question behind &lt;strong&gt;access-sentinel&lt;/strong&gt;, a simulated patient-records access system I built to work through how healthcare software actually handles this tension, not in theory, but in the specific moments where the "right" answer isn't obvious.&lt;/p&gt;




&lt;h2&gt;
  
  
  The setup: RBAC is the easy part
&lt;/h2&gt;

&lt;p&gt;Role-based access control itself isn't the hard problem. Doctors get clinical and billing data, nurses get clinical only, billing staff get financial data only, and admins (deliberately) get none of it directly; they manage the platform, not patient records. That's a straightforward policy to write and enforce at the API layer.&lt;/p&gt;

&lt;p&gt;The hard problems start at the edges: what happens in an emergency, and what happens when part of the system is down.&lt;/p&gt;




&lt;h2&gt;
  
  
  Edge case one: break-glass access
&lt;/h2&gt;

&lt;p&gt;Real healthcare systems have a well-known pattern called "break-glass", a clinician can override normal access restrictions in a declared emergency. The tension is obvious once you say it out loud: &lt;strong&gt;you can never let "emergency" become an unmonitored backdoor, but you also can never let strict access control block someone from saving a life.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I implemented this as an explicit override: a request can include a break-glass header and a required justification reason. Two things I was careful about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Only clinical roles can break-glass.&lt;/strong&gt; A billing or admin account requesting an emergency override gets a flat &lt;code&gt;403&lt;/code&gt;, there's no legitimate emergency-care reason for those roles to need it, so the override surface is deliberately narrow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A justification is mandatory, not optional.&lt;/strong&gt; A break-glass request without a reason gets rejected with a &lt;code&gt;400&lt;/code&gt; before it ever touches patient data. The override isn't free, you have to state why.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every override is logged and counted separately&lt;/strong&gt; from normal access, specifically so a spike in break-glass usage is visible as an anomaly signal, not buried in normal traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mechanism doesn't prevent misuse, nothing purely technical can, because the whole point is that a human is allowed to override the rules. What it does is make misuse expensive to hide and cheap to detect after the fact.&lt;/p&gt;




&lt;h2&gt;
  
  
  Edge case two: what happens when the audit log is down
&lt;/h2&gt;

&lt;p&gt;This is the design decision I spent the most time on. If every access needs to be logged, what happens to a request when the logging store itself is unreachable?&lt;/p&gt;

&lt;p&gt;There are two clean-sounding answers, and they're both wrong on their own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fail closed&lt;/strong&gt; (reject all requests until logging is restored) is the "safe" choice, nothing goes unlogged, but it means a doctor can't pull up a patient's chart during an outage, which is a genuinely dangerous failure mode in an emergency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fail open&lt;/strong&gt; (let everything through, log later) keeps care running, but if "log later" quietly never happens, you've built an access-control system with no actual record of who saw what.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I ended up with a hybrid, split by role: clinical reads (doctor, nurse) fail open, the request succeeds, the response carries a header flagging the system as degraded, and the access event gets buffered in memory to flush to the audit store once it recovers. Non-clinical reads (billing) fail closed, a &lt;code&gt;503&lt;/code&gt;, because there's no emergency-care justification for blocking that traffic, so strict compliance wins by default.&lt;/p&gt;

&lt;p&gt;I tested this by actually forcing the audit store offline under sustained load, not just a single request, and watching Grafana through the outage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The buffered-log counter climbed steadily during the outage, confirming events were queuing rather than silently dropping&lt;/li&gt;
&lt;li&gt;Billing requests sat flat at zero (correctly blocked) the whole time&lt;/li&gt;
&lt;li&gt;Once the store came back online, the buffered counter dropped back to zero, the queued events actually flushed, not just accumulated forever&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9tof8t0ioyx9zz1m5qyo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9tof8t0ioyx9zz1m5qyo.png" alt="Dashboard during outage" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhmxooncvd9zrsc22fcmn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhmxooncvd9zrsc22fcmn.png" alt="Dashboard after recovery" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That last part mattered most to me. "Fail open" is an easy design decision to state and a much harder one to prove, the difference between "available" and "available and honest about what happened" is exactly the buffered-and-flushed behavior, not just the initial &lt;code&gt;200&lt;/code&gt; response.&lt;/p&gt;




&lt;h2&gt;
  
  
  The tension I didn't expect: immutability vs. the right to be forgotten
&lt;/h2&gt;

&lt;p&gt;The audit log is append-only by design, every entry is chained to the previous one with a SHA-256 hash, and any attempt to edit or delete a log entry is rejected outright. That's the right call for audit integrity: if the log can be edited, it's not actually proof of anything.&lt;/p&gt;

&lt;p&gt;But that same immutability runs directly into privacy regulations like GDPR's "right to be forgotten," which require that personal data be deletable on request. An access log that can never be edited or deleted is, by construction, incompatible with a legal right to erasure.&lt;/p&gt;

&lt;p&gt;Real systems handle this with patterns like pseudonymized lookup tables, the immutable log stores a reference ID, not the person's actual identity, and the identity mapping (which can be deleted) lives separately. I didn't build that layer here, but naming the tension directly, rather than pretending an append-only log is a strictly better design with no trade-offs, felt more honest than leaving it out.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this project didn't try to be
&lt;/h2&gt;

&lt;p&gt;This isn't HIPAA-compliant software, and I'm not claiming it models every real constraint a production healthcare system would need — real deployments have encryption-at-rest requirements, formal compliance audits, and legal review this project never touched. What it does model honestly is the shape of the actual trade-offs: strict-but-blocking versus available-but-riskier, and the fact that a good system doesn't pick one side of that trade-off globally, it picks differently depending on what's actually at stake for a given request.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Repo: &lt;a href="https://github.com/aashiruu/access-sentinel" rel="noopener noreferrer"&gt;github.com/aashiruu/access-sentinel&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>fastapi</category>
      <category>postgres</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Building a Chaos Engineering CLI Taught Me Why "It Recovered" Isn't Enough</title>
      <dc:creator>Okikiola Ashiru</dc:creator>
      <pubDate>Sat, 01 Aug 2026 14:03:57 +0000</pubDate>
      <link>https://dev.to/0xkikiola/building-a-chaos-engineering-cli-taught-me-why-it-recovered-isnt-enough-2mh3</link>
      <guid>https://dev.to/0xkikiola/building-a-chaos-engineering-cli-taught-me-why-it-recovered-isnt-enough-2mh3</guid>
      <description>&lt;p&gt;After building &lt;code&gt;ledger-sentinel&lt;/code&gt;, a payment system focused on correctness under concurrent load, I wanted to go one level deeper: not just &lt;em&gt;"does the system behave correctly,"&lt;/em&gt; but &lt;em&gt;"does the system recover when something actually breaks."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's the premise behind &lt;strong&gt;&lt;code&gt;fault-sentinel&lt;/code&gt;&lt;/strong&gt;, a lightweight Kubernetes-native CLI I built in Go to deliberately inject failures (killing pods, adding network latency, generating CPU load) and observe what actually happens.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why build your own tool instead of just using an existing one?
&lt;/h2&gt;

&lt;p&gt;There are established chaos engineering tools (Chaos Mesh, LitmusChaos) that do this more comprehensively. I built &lt;code&gt;fault-sentinel&lt;/code&gt; anyway for a specific reason: I wanted to understand the mechanics from the inside, not just run someone else's custom resources.&lt;/p&gt;

&lt;p&gt;Writing the pod-eviction logic myself using &lt;code&gt;k8s.io/client-go&lt;/code&gt; means I actually know what a graceful deletion versus a forced deletion does at the API level, rather than just knowing a CRD exists for it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is an experimental learning project built to explore chaos injection concepts and Go platform engineering principles, not a production tool.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Three Experiments
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pod Termination (&lt;code&gt;kill-pod&lt;/code&gt;):&lt;/strong&gt; Selects a pod by label selector and deletes it to verify whether the deployment's &lt;code&gt;ReplicaSet&lt;/code&gt; controller notices and replaces it, and how fast reconciliation occurs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7z414bfs1ncyofx7ip7v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7z414bfs1ncyofx7ip7v.png" alt="Pod termination and self-healing" width="512" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Network Latency (&lt;code&gt;network-delay&lt;/code&gt;):&lt;/strong&gt; Uses Linux Traffic Control (&lt;code&gt;tc netem&lt;/code&gt;) inside the target container's network namespace to inject artificial packet delay, automatically triggering a cleanup after the experiment window.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CPU Stress (&lt;code&gt;stress-cpu&lt;/code&gt;):&lt;/strong&gt; Spins up compute load across a configurable number of cores for a set duration to observe how the workload performs under compute starvation.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each experiment executes through a Cobra-based CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Terminate a pod matching a label&lt;/span&gt;
./bin/fault-cli kill-pod &lt;span class="nt"&gt;--namespace&lt;/span&gt; default &lt;span class="nt"&gt;--label-selector&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;target-app

&lt;span class="c"&gt;# Inject 200ms network delay for 30 seconds&lt;/span&gt;
./bin/fault-cli network-delay &lt;span class="nt"&gt;--namespace&lt;/span&gt; default &lt;span class="nt"&gt;--label-selector&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;target-app &lt;span class="nt"&gt;--delay&lt;/span&gt; 200ms &lt;span class="nt"&gt;--duration&lt;/span&gt; 30s

&lt;span class="c"&gt;# Apply CPU stress across 2 cores for 30 seconds&lt;/span&gt;
./bin/fault-cli stress-cpu &lt;span class="nt"&gt;--duration&lt;/span&gt; 30s &lt;span class="nt"&gt;--cores&lt;/span&gt; 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The design decision I spent the most time on: how much access does this tool actually need?
&lt;/h2&gt;

&lt;p&gt;A chaos tool is, by definition, something that deletes pods and manipulates network behavior in a cluster. That's a meaningful amount of trust to grant a piece of software, so I wanted the access model to be as narrow as it could be.&lt;/p&gt;

&lt;p&gt;Two things came out of that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RBAC scoping:&lt;/strong&gt; &lt;code&gt;kill-pod&lt;/code&gt; only needs &lt;code&gt;list&lt;/code&gt; and &lt;code&gt;delete&lt;/code&gt; permissions on pods in the target namespace — not cluster-wide access, not access to secrets or other resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No persistent daemon:&lt;/strong&gt; fault-sentinel doesn't run as a long-lived agent inside the cluster. It uses standard &lt;code&gt;client-go&lt;/code&gt; calls and SPDY exec connections for the duration of an experiment, then it's done. There's no always-on process with standing permissions waiting to be exploited, the tool is only as dangerous as the moment you're actively running it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trade-off here is availability, not just access: a tool with no daemon can't schedule automatic recurring chaos experiments the way Chaos Mesh can. For a learning project focused on understanding failure mechanics rather than running a continuous chaos program, that trade-off made sense.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the network-delay injection actually required
&lt;/h2&gt;

&lt;p&gt;This was the most fiddly of the three experiments to get right. Injecting latency via &lt;code&gt;tc netem&lt;/code&gt; requires the &lt;code&gt;NET_ADMIN&lt;/code&gt; Linux capability inside the target container — without it, the &lt;code&gt;tc&lt;/code&gt; command inside the pod simply fails with a permissions error. That means the target application's pod spec needs &lt;code&gt;NET_ADMIN&lt;/code&gt; added to its &lt;code&gt;securityContext&lt;/code&gt;, which is itself a decision worth thinking about: you're granting the target application's container a capability it doesn't normally need, purely so it can be a valid subject for chaos testing.&lt;/p&gt;

&lt;p&gt;That's a real trade-off, not a footnote, running chaos experiments against a workload means loosening that workload's security posture slightly, at least for network-based experiments. In a real environment, you'd want a dedicated, tightly scoped service account and probably a separate sidecar with the capability, rather than granting it to the application container directly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fty24mfpzhst2cg7i90l5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fty24mfpzhst2cg7i90l5.png" alt="Network delay injection and automatic cleanup" width="512" height="203"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Telemetry: making sure the experiment itself is observable
&lt;/h2&gt;

&lt;p&gt;An experiment you can't measure isn't really an experiment. fault-sentinel exposes Prometheus metrics on &lt;code&gt;:8080/metrics&lt;/code&gt; during every run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;chaos_experiments_total{experiment_type, status}&lt;/code&gt; — how many experiments ran, and whether they completed or errored&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chaos_injected_faults_total{target_pod, fault_type}&lt;/code&gt; — which specific pods were hit, and with what&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chaos_experiment_duration_seconds{experiment_type}&lt;/code&gt; — how long each experiment actually took&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scraping this mid-experiment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; http://localhost:8080/metrics | &lt;span class="nb"&gt;grep &lt;/span&gt;chaos_
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc7443oli81ln9ejbbyo1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc7443oli81ln9ejbbyo1.png" alt="Prometheus metrics scrape output" width="512" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;chaos_injected_faults_total&lt;/code&gt; metric tracks the cumulative count of successful fault injections labeled by &lt;code&gt;fault_type&lt;/code&gt; and target &lt;code&gt;target_pod&lt;/code&gt;. In the screenshot above, the counter value of 1 reflects a single active 250ms latency experiment targeting pod &lt;code&gt;payment-api-667fdccc65-gwmfl&lt;/code&gt;. Successive runs against other pods or repeated injections will increment this value per label combination across the lifetime of the telemetry server instance.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What I actually verified, not just designed
&lt;/h2&gt;

&lt;p&gt;The CI pipeline (GitHub Actions) runs &lt;code&gt;golangci-lint&lt;/code&gt;, unit tests with Go's race detector enabled (&lt;code&gt;go test -race&lt;/code&gt;), builds a multi-stage Docker image, and runs a Trivy vulnerability scan on the built image for critical/high severities before anything is considered done. The race detector matters specifically here, a chaos tool that has its own concurrency bugs while testing other systems' concurrency behavior would be a bad joke.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy55aajw16q0zdoaxq8sq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy55aajw16q0zdoaxq8sq.png" alt="CI pipeline passing" width="512" height="236"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What this project didn't try to be
&lt;/h2&gt;

&lt;p&gt;This isn't a replacement for Chaos Mesh or Litmus, and I'm not claiming it should be used against a real production cluster. It doesn't have scheduled/recurring experiments, it doesn't have a web UI, and it doesn't handle multi-cluster orchestration. What it does have is a clear, small surface area that I understand completely, because I built every part of it... which was the actual point.&lt;/p&gt;

&lt;p&gt;The lesson that stuck with me most: recovery isn't binary. A pod coming back after being killed isn't the same as the system recovering, you have to actually watch what happens to in-flight requests, latency, and error rates during the gap, not just confirm the pod count went back to normal. That's the difference between "it healed" and "it healed in a way that didn't hurt anyone using it."&lt;/p&gt;




&lt;p&gt;Repo: &lt;a href="https://github.com/aashiruu/fault-sentinel" rel="noopener noreferrer"&gt;https://github.com/aashiruu/fault-sentinel&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>kubernetes</category>
      <category>devops</category>
      <category>chaosengineering</category>
    </item>
    <item>
      <title>What Would a Fintech Payment System's DevOps Setup Actually Look Like?</title>
      <dc:creator>Okikiola Ashiru</dc:creator>
      <pubDate>Wed, 29 Jul 2026 14:10:43 +0000</pubDate>
      <link>https://dev.to/0xkikiola/what-would-a-fintech-payment-systems-devops-setup-actually-look-like-1pd</link>
      <guid>https://dev.to/0xkikiola/what-would-a-fintech-payment-systems-devops-setup-actually-look-like-1pd</guid>
      <description>&lt;p&gt;Every industry has different constraints that shape its infrastructure decisions. Banking cares about compliance and audit trails. E-commerce cares about traffic spikes on sale days. Fintech payment systems care about something more specific: &lt;strong&gt;money cannot be created or destroyed by accident.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqv774tcnjvcl5prd2x9s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqv774tcnjvcl5prd2x9s.png" alt=" " width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If a request gets retried because of a flaky network connection, a customer should never be charged twice. If two requests hit the database at the same time, the ledger should never end up in an inconsistent state. This one constraint, correctness under concurrency and failure, ends up driving almost every infrastructure decision in a payment system.&lt;/p&gt;

&lt;p&gt;I wanted to understand this properly, so I built a small payment gateway simulation called &lt;strong&gt;ledger-sentinel&lt;/strong&gt; to work through the actual engineering problems, not just read about them. Here's what the DevOps/infrastructure thinking behind a system like this looks like, using what I built as a concrete example.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core problem: idempotency
&lt;/h2&gt;

&lt;p&gt;The first design question in any payment system is: &lt;strong&gt;what happens when the same request arrives twice?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This happens constantly in production; a client times out and retries, a load balancer resends a request, a mobile app has a flaky connection and fires the same "pay now" tap twice. If your system isn't built to handle this, you get duplicate charges.&lt;/p&gt;

&lt;p&gt;The standard pattern is an &lt;strong&gt;idempotency key&lt;/strong&gt;: the client sends a unique key with each logical transaction, and the server guarantees that request only actually processes once, no matter how many times it arrives.&lt;/p&gt;

&lt;p&gt;In ledger-sentinel, I implemented this with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A Redis distributed lock&lt;/strong&gt; (SET NX EX) that acts as a fast, short-lived gatekeeper... the first request to arrive with a given key gets the lock, any duplicate arriving while it's still processing gets rejected (HTTP 409) instead of double-processing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A response cache layered&lt;/strong&gt; on top, so once a request has actually completed, any later retry with the same key gets served the original cached response (HTTP 200) instead of hitting the database again&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the difference between "the system happened to work in testing" and "the system is provably safe under concurrent retries", and it's the first thing I'd want to verify actually holds before trusting any payment infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why async settlement, not synchronous processing
&lt;/h2&gt;

&lt;p&gt;A naive payment API might try to validate, charge, and update the ledger all within a single HTTP request. This is a mistake at any real scale, because it means the client is waiting on your slowest downstream dependency (usually the database) for every single request, and a slow ledger write becomes a slow, unreliable API.&lt;/p&gt;

&lt;p&gt;The fix is decoupling ingestion from settlement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The API validates the request and idempotency key, then pushes the transaction onto a RabbitMQ queue&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A separate worker process consumes the queue and does the actual ledger update&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The client gets a fast response (validated and queued), and the ledger settles asynchronously&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This also gives you backpressure control, if the worker is falling behind under a traffic burst, messages queue up safely instead of the whole system falling over. I set a consumer prefetch limit (prefetch_count=10) specifically so the worker never grabs more in-flight work than it can actually handle at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the ledger itself still needs strict locking
&lt;/h2&gt;

&lt;p&gt;Queueing solves the "don't block the client" problem, but it doesn't solve the "two workers processing related transactions at the same time" problem. For that, the actual database work still needs strict consistency guarantees.&lt;/p&gt;

&lt;p&gt;I used &lt;strong&gt;PostgreSQL row-level locking&lt;/strong&gt; (SELECT ... FOR UPDATE) so that when a worker is updating a specific ledger balance, no other transaction can read or write that same row until the lock releases. This is slower than an unlocked read, but for a ledger, "slower but always correct" beats "fast but occasionally wrong", the entire point of a ledger is that the numbers are always right.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I actually verified this wasn't just "should work in theory"
&lt;/h2&gt;

&lt;p&gt;Design decisions are cheap to write down and easy to get wrong in practice. So I stress-tested it with k6, firing over 1,000 concurrent transaction requests at the system, some with duplicate idempotency keys on purpose, and checked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Zero duplicate charges&lt;/strong&gt; — verified directly against the database (GROUP BY idempotency_key HAVING COUNT(*) &amp;gt; 1 returned nothing)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;p99 latency&lt;/strong&gt; stayed sub-second even during the burst, and recovered to ~4–8ms once the burst normalized and requests were hitting the cache&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;100% success rate, zero HTTP 5xx errors, across the full load test&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa69ygbzvy5nfwcoenj8c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa69ygbzvy5nfwcoenj8c.png" alt=" " width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also watched this fail in interesting ways during development, for example, my first version of the load test accidentally reused the same idempotency key across requests, which meant Redis was serving cached responses without ever reaching RabbitMQ at all. The queue graphs looked completely flat, which looked like a bug until I realized the test script itself was wrong, not the system. That kind of debugging, figuring out whether the system or the test is lying to you, is most of what this work actually is.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd add next if this were a real production system
&lt;/h2&gt;

&lt;p&gt;This project is a simulation, not a production system, and there are things a real fintech payment platform would need that I haven't built here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Multi-region failover, since payment infra can't have a single point of failure&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Real reconciliation against an external payment processor's records, not just internal consistency&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Proper secrets management and PCI-DSS-aligned access controls, rather than local .env files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Chaos testing (deliberately killing a worker mid-transaction) rather than just load testing&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the core lesson holds even at small scale: in payment systems, the interesting infrastructure decisions aren't about which cloud provider or which orchestrator you pick. They're about how you handle the moment two things happen at exactly the same time.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/aashiruu/ledger-sentinel" rel="noopener noreferrer"&gt;https://github.com/aashiruu/ledger-sentinel&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>architecture</category>
      <category>redis</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Hi, I'm Okikiola. Cloud &amp; DevOps Engineer working through infrastructure problems in public</title>
      <dc:creator>Okikiola Ashiru</dc:creator>
      <pubDate>Wed, 29 Jul 2026 10:05:55 +0000</pubDate>
      <link>https://dev.to/0xkikiola/hi-im-okikiola-cloud-devops-engineer-working-through-infrastructure-problems-in-public-3391</link>
      <guid>https://dev.to/0xkikiola/hi-im-okikiola-cloud-devops-engineer-working-through-infrastructure-problems-in-public-3391</guid>
      <description>&lt;p&gt;Hi, I'm Okikiola — a Cloud &amp;amp; DevOps Engineer based in Lagos, Nigeria.&lt;/p&gt;

&lt;p&gt;I came into this field a little sideways. My background is in Biochemistry, but somewhere along the way I got pulled toward infrastructure... the kind of problems where something breaks under load and you have to figure out why, or where a system needs to survive a traffic burst without falling over or double-charging someone.&lt;/p&gt;

&lt;p&gt;That pull turned into two years of hands-on work: provisioning cloud environments on AWS and OCI, building CI/CD pipelines, and setting up the observability stacks that catch failures before a customer notices them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I work with day to day&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure as Code&lt;/strong&gt;: Modular Terraform across AWS and OCI, managing VPCs, IAM policies, and multi-node EKS clusters across projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD&lt;/strong&gt;: GitHub Actions workflows for automated linting, container builds, and deployment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability&lt;/strong&gt;: Prometheus, Grafana, and Loki for metrics, logs, and alerting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation&lt;/strong&gt;: Go and Python (Boto3) scripts for the unglamorous but necessary work, cleaning up orphaned cloud resources, enforcing tagging policies, automating backup rotations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why I'm writing here&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I've started building deeper projects specifically to understand infrastructure problems at the system level, not just to add tools to a resume.&lt;/p&gt;

&lt;p&gt;My most recent one, &lt;em&gt;ledger-sentinel&lt;/em&gt;, is a simulated fintech payment gateway I built to work through idempotency locking (Redis SET NX EX), async settlement via RabbitMQ, and database consistency under concurrent load. It's the kind of system where "it worked in my test" and "it's actually safe against double-charges" are two very different claims, and I wanted to prove the second one, not just assume it.&lt;/p&gt;

&lt;p&gt;I plan to write about this project and others like it, real architecture decisions, load-test numbers, what broke, and what I'd still need to add before calling any of it production-ready. I'd rather be upfront about the gap between a personal project and a production system than pretend it isn't there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I'm currently digging into&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Right now I'm spending time on distributed lock contention patterns, Redis cache short-circuiting, and queue backpressure mechanics, mostly because ledger-sentinel showed me how much nuance sits behind "just add a distributed lock" once thousands of requests hit the same endpoint at once.&lt;/p&gt;

&lt;p&gt;If you work in DevOps, SRE, or platform engineering, or you're navigating a non-traditional path into cloud infrastructure yourself, I'd like to connect. Always glad to talk through Terraform patterns, observability setups, or a race condition you've had to hunt down.&lt;/p&gt;

&lt;p&gt;GitHub: github.com/aashiruu&lt;br&gt;
LinkedIn: linkedin.com/in/okikiolaashiru&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cloud</category>
      <category>architecture</category>
      <category>introduction</category>
    </item>
  </channel>
</rss>
