<?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: Roman_14K</title>
    <description>The latest articles on DEV Community by Roman_14K (@__yammi).</description>
    <link>https://dev.to/__yammi</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%2F3887536%2Fccc8680e-87a6-4646-b6d6-6bb4ad2fe4cc.jpg</url>
      <title>DEV Community: Roman_14K</title>
      <link>https://dev.to/__yammi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/__yammi"/>
    <language>en</language>
    <item>
      <title>User X changed the order -except a queued job did. Here's the missing piece in Laravel audit logs.</title>
      <dc:creator>Roman_14K</dc:creator>
      <pubDate>Mon, 15 Jun 2026 08:55:52 +0000</pubDate>
      <link>https://dev.to/__yammi/user-x-changed-the-order-except-a-queued-job-did-heres-the-missing-piece-in-laravel-audit-logs-odc</link>
      <guid>https://dev.to/__yammi/user-x-changed-the-order-except-a-queued-job-did-heres-the-missing-piece-in-laravel-audit-logs-odc</guid>
      <description>&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.amazonaws.com%2Fuploads%2Farticles%2Fkce2zukctvm5v8jmmaow.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.amazonaws.com%2Fuploads%2Farticles%2Fkce2zukctvm5v8jmmaow.png" alt=" " width="800" height="815"&gt;&lt;/a&gt;&lt;br&gt;
An order suddenly moved to &lt;code&gt;refunded&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You open the audit log and see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order #42 updated
By: System
Changed: status = refunded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great.&lt;/p&gt;

&lt;p&gt;But who actually clicked the button?&lt;/p&gt;

&lt;p&gt;Support? The customer? An admin? A scheduled task? Another job?&lt;/p&gt;

&lt;p&gt;The audit trail has no answer.&lt;/p&gt;

&lt;p&gt;That problem is what led me to build Yammi Audit Log.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with audit logs in queue-heavy applications
&lt;/h2&gt;

&lt;p&gt;Most Laravel audit packages are good at answering one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What changed?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In modern applications, that's often not enough.&lt;/p&gt;

&lt;p&gt;A typical flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP request
    ↓
Service
    ↓
Queue
    ↓
Job
    ↓
Model update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By the time the database row is updated, the actual write is being performed by a queue worker.&lt;/p&gt;

&lt;p&gt;The audit log ends up saying something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Changed by: System
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Changed by: Queue Worker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Technically correct.&lt;/p&gt;

&lt;p&gt;Practically useless.&lt;/p&gt;

&lt;p&gt;During an incident, the question people actually ask is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Who initiated this change, and what execution path led to it?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Tracking provenance instead of just changes
&lt;/h2&gt;

&lt;p&gt;Yammi Audit Log records three separate concepts for every change.&lt;/p&gt;

&lt;h3&gt;
  
  
  Actor
&lt;/h3&gt;

&lt;p&gt;Who directly executed the write.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"job"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ChargeOrder"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Actors can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;user&lt;/li&gt;
&lt;li&gt;job&lt;/li&gt;
&lt;li&gt;command&lt;/li&gt;
&lt;li&gt;scheduler&lt;/li&gt;
&lt;li&gt;system&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Origin
&lt;/h3&gt;

&lt;p&gt;Who started the entire chain.&lt;/p&gt;

&lt;p&gt;Imagine a user clicks "Pay".&lt;/p&gt;

&lt;p&gt;That dispatches a job.&lt;/p&gt;

&lt;p&gt;The job dispatches another job.&lt;/p&gt;

&lt;p&gt;The final database write is executed by a queue worker, but the origin remains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Correlation ID
&lt;/h3&gt;

&lt;p&gt;A single identifier shared across the entire execution chain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request
  ↓
Job A
  ↓
Job B
  ↓
Order #42 updated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That correlation ID allows you to reconstruct the full cascade.&lt;/p&gt;

&lt;p&gt;[trace screenshot]&lt;/p&gt;

&lt;p&gt;Now the audit log answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What caused this change?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;instead of only:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What code wrote this row?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The implementation is intentionally simple.&lt;/p&gt;

&lt;p&gt;The package listens globally to Eloquent model events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;created
updated
deleted
restored
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a change occurs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A field-level diff is built.&lt;/li&gt;
&lt;li&gt;Sensitive values are redacted (&lt;code&gt;password&lt;/code&gt;, &lt;code&gt;token&lt;/code&gt;, &lt;code&gt;api_key&lt;/code&gt;, etc.).&lt;/li&gt;
&lt;li&gt;The current actor is resolved.&lt;/li&gt;
&lt;li&gt;The origin context is serialized into queued jobs.&lt;/li&gt;
&lt;li&gt;A correlation ID ties the entire chain together.&lt;/li&gt;
&lt;li&gt;An audit record is written.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No per-model registration is required for basic auditing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'John Doe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The change is captured automatically.&lt;/p&gt;

&lt;p&gt;[dashboard screenshot]&lt;/p&gt;

&lt;h2&gt;
  
  
  A few things built on top of that context
&lt;/h2&gt;

&lt;p&gt;Once every change carries execution provenance, some interesting features become possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tamper-evident history
&lt;/h3&gt;

&lt;p&gt;Optionally hash-chain every record and verify integrity later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan audit-log:verify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Time Machine
&lt;/h3&gt;

&lt;p&gt;Reconstruct the exact state of a record at any point in time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;AuditLog&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;stateAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'2026-03-03'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Anomaly Detection
&lt;/h3&gt;

&lt;p&gt;Detect suspicious patterns such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;change bursts&lt;/li&gt;
&lt;li&gt;mass deletions&lt;/li&gt;
&lt;li&gt;off-hours activity&lt;/li&gt;
&lt;li&gt;unusually large write cascades&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because the package already understands the execution chain, it can reason about behavior, not just rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Installation takes a couple of minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require romalytar/yammi-audit-log-laravel

php artisan migrate

php artisan audit-log:ui &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/audit-log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and start seeing not only what changed, but how that change got there.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/RomaLytar/yammi-audit-log" rel="noopener noreferrer"&gt;https://github.com/RomaLytar/yammi-audit-log&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If this kind of execution traceability is something you've missed in Laravel, I'd love to hear your feedback.&lt;br&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.amazonaws.com%2Fuploads%2Farticles%2Fft0qrlk2eq50wrwvzc8a.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.amazonaws.com%2Fuploads%2Farticles%2Fft0qrlk2eq50wrwvzc8a.png" alt=" " width="800" height="810"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I built a Laravel queue monitoring tool because I got tired of not knowing what my jobs actually do</title>
      <dc:creator>Roman_14K</dc:creator>
      <pubDate>Sun, 19 Apr 2026 16:12:58 +0000</pubDate>
      <link>https://dev.to/__yammi/i-built-a-laravel-queue-monitoring-tool-because-i-got-tired-of-not-knowing-what-my-jobs-actually-do-33lh</link>
      <guid>https://dev.to/__yammi/i-built-a-laravel-queue-monitoring-tool-because-i-got-tired-of-not-knowing-what-my-jobs-actually-do-33lh</guid>
      <description>&lt;p&gt;At some point I realized I don’t really understand what’s going on with my queues.&lt;br&gt;
I mean, yeah:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;jobs are running&lt;/li&gt;
&lt;li&gt;workers are alive&lt;/li&gt;
&lt;li&gt;logs exist somewhere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But if I try to answer simple questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;did this job actually do what it was supposed to do?&lt;/li&gt;
&lt;li&gt;or did it just “successfully complete”?&lt;/li&gt;
&lt;li&gt;where do things silently break?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;— I don’t really have good answers. The most annoying part — silent failures. There’s a type of bug that’s especially frustrating.&lt;br&gt;
A job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;runs&lt;/li&gt;
&lt;li&gt;throws no errors&lt;/li&gt;
&lt;li&gt;&lt;p&gt;finishes with success&lt;br&gt;
…and does absolutely nothing.&lt;br&gt;
I thought it was rare, but once I started digging, I found several cases like this. What helped me spot them was looking at execution time.&lt;br&gt;
Something like: normally the job takes ~500ms, sometimes it finishes in 5ms, that’s… suspicious 🙂&lt;br&gt;
That’s how I found jobs that were “successful” but effectively doing nothing. At some point I just wanted a clear view. Nothing fancy.&lt;br&gt;
Just open a page and understand:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;what’s happening right now&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;what’s failing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;what looks weird&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plus a few practical things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;see all retries&lt;/li&gt;
&lt;li&gt;understand failure reasons&lt;/li&gt;
&lt;li&gt;group recurring errors&lt;/li&gt;
&lt;li&gt;retry not just one job, but many&lt;/li&gt;
&lt;li&gt;sometimes fix the payload and re-run&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And of course alerts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slack&lt;/li&gt;
&lt;li&gt;Webhook&lt;/li&gt;
&lt;li&gt;PagerDuty for critical stuff
So I built a small package, installation is basically:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;composer require romalytar/yammi-jobs-monitoring-laravel&lt;br&gt;
php artisan migrate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then you just open:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/jobs-monitor&lt;/code&gt;&lt;br&gt;
No heavy setup, it just works.&lt;br&gt;
What it actually shows. The main idea is: not just status, but behavior.&lt;br&gt;
You can open any job and see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;all attempts&lt;/li&gt;
&lt;li&gt;errors&lt;/li&gt;
&lt;li&gt;&lt;p&gt;execution time for each try&lt;br&gt;
Which already gives way more insight than just “failed / success”.&lt;br&gt;
There’s also some basic stats:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;which jobs fail the most&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;slowest jobs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;retry rate&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Failed jobs (DLQ) are actually usable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;retry&lt;/li&gt;
&lt;li&gt;edit &amp;amp; retry (JSON payload)&lt;/li&gt;
&lt;li&gt;bulk operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One thing I personally like a lot — error grouping.&lt;br&gt;
Instead of scrolling through identical stack traces, you see grouped failures and immediately understand:&lt;br&gt;
“ok, this all comes from the same issue”.&lt;br&gt;
And probably the most useful part — anomaly detection.&lt;br&gt;
If a job suddenly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;becomes much slower&lt;/li&gt;
&lt;li&gt;or suspiciously fast&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;—it gets flagged.&lt;/p&gt;

&lt;p&gt;Those “too fast” cases are often silent failures.&lt;br&gt;
Also included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;worker heartbeat (you see when workers disappear)&lt;/li&gt;
&lt;li&gt;scheduled task monitoring&lt;/li&gt;
&lt;li&gt;alerts (Slack / Webhook / PagerDuty / etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The whole idea is pretty simple Not to build “another tool”.&lt;br&gt;
But to answer one question: what is actually happening in my queues?&lt;br&gt;
Would love some feedback&lt;br&gt;
If anyone tries it, I’d be really interested in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what’s missing&lt;/li&gt;
&lt;li&gt;what feels unnecessary&lt;/li&gt;
&lt;li&gt;what works well in real projects&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.amazonaws.com%2Fuploads%2Farticles%2Fm8nairwj3kjv4x8cm81b.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.amazonaws.com%2Fuploads%2Farticles%2Fm8nairwj3kjv4x8cm81b.png" alt=" " width="800" height="794"&gt;&lt;/a&gt;&lt;br&gt;
Here’s the repo if you want to check it out:&lt;br&gt;
&lt;a href="https://github.com/RomaLytar/yammi-jobs-monitoring-laravel" rel="noopener noreferrer"&gt;https://github.com/RomaLytar/yammi-jobs-monitoring-laravel&lt;/a&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
