<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom">
  <title>@imqueue Blog</title>
  <subtitle>Articles about message-queue RPC for Node.js &amp; TypeScript microservices.</subtitle>
  <link href="https://imqueue.org/blog/feed.xml" rel="self"/>
  <link href="https://imqueue.org/blog/"/>
  <id>https://imqueue.org/blog/</id>
  <updated>2026-09-08T00:00:00Z</updated>
  <author><name>@imqueue</name><uri>https://imqueue.org/</uri></author><entry>
    <title>Fifty callers, one query: the cache stampede and the decorator that ends it</title>
    <link href="https://imqueue.org/blog/cache-stampede-single-flight-nodejs/"/>
    <id>https://imqueue.org/blog/cache-stampede-single-flight-nodejs/</id>
    <published>2026-09-08T00:00:00Z</published>
    <updated>2026-09-08T00:00:00Z</updated><author><name>Mykhailo Stadnyk</name><uri>https://imqueue.org/blog/authors/mykhailo-stadnyk/</uri></author><category term="cache"/><category term="patterns"/><category term="performance"/><category term="rpc"/><summary type="text">A cache is at its most useless in the one moment you need it: the key is cold, fifty requests miss it together, and fifty copies of the same query hit the database. Measured — and measured again with one line above the method that makes it one query, one result, fifty callers served.</summary>
  </entry><entry>
    <title>The contract your services already publish: contract testing for Node.js microservices</title>
    <link href="https://imqueue.org/blog/contract-testing-generated-clients/"/>
    <id>https://imqueue.org/blog/contract-testing-generated-clients/</id>
    <published>2026-09-04T00:00:00Z</published>
    <updated>2026-09-04T00:00:00Z</updated><author><name>Serhiy Morenko</name><uri>https://imqueue.org/blog/authors/serhiy-morenko/</uri></author><category term="testing"/><category term="types"/><category term="clients"/><category term="dx"/><summary type="text">Contract testing exists because two services can agree on a shape today and disagree on it next Thursday, with nothing in either repository to notice. If your clients are generated, most of that machinery is already built for you — and the part that is left is not the part the tooling advertises. Here is what an @imqueue service publishes about itself, how to pin it in a test that needs no broker, and the one place the contract can quietly disagree with your TypeScript.</summary>
  </entry><entry>
    <title>Meeting compliance: how to talk to your Redis broker over TLS</title>
    <link href="https://imqueue.org/blog/tls-redis-broker-nodejs/"/>
    <id>https://imqueue.org/blog/tls-redis-broker-nodejs/</id>
    <published>2026-09-01T00:00:00Z</published>
    <updated>2026-09-01T00:00:00Z</updated><author><name>Mykhailo Stadnyk</name><uri>https://imqueue.org/blog/authors/mykhailo-stadnyk/</uri></author><category term="security"/><category term="transport"/><category term="queue"/><summary type="text">The questionnaire asks whether data is encrypted in transit, and you know the answer for the edge. Then you remember the broker — the one connection every service holds open all day, carrying every argument and every return value, and speaking a protocol that puts them on the wire as text. Here is what encrypting it takes, what it costs, and the two places it is easy to get wrong.</summary>
  </entry><entry>
    <title>Checking an IP against 10,000 networks without comparing it to 10,000 networks</title>
    <link href="https://imqueue.org/blog/ip-allow-lists-cidr-nodejs/"/>
    <id>https://imqueue.org/blog/ip-allow-lists-cidr-nodejs/</id>
    <published>2026-08-28T00:00:00Z</published>
    <updated>2026-08-28T00:00:00Z</updated><author><name>Mykhailo Stadnyk</name><uri>https://imqueue.org/blog/authors/mykhailo-stadnyk/</uri></author><category term="security"/><category term="performance"/><category term="patterns"/><summary type="text">Every request asks the same question — is this one of ours? — and the loop you wrote to answer it gets slower every time someone adds a partner range. Here is how to answer it in logarithmic time instead, what an address really is once you stop treating it as a string, and the quiet precondition that a fast implementation must uphold or it will lie to you.</summary>
  </entry><entry>
    <title>Typed at compile time, unchecked on the wire: runtime validation for TypeScript services</title>
    <link href="https://imqueue.org/blog/runtime-validation-typescript-services/"/>
    <id>https://imqueue.org/blog/runtime-validation-typescript-services/</id>
    <published>2026-08-25T00:00:00Z</published>
    <updated>2026-08-25T00:00:00Z</updated><author><name>Serhiy Morenko</name><uri>https://imqueue.org/blog/authors/serhiy-morenko/</uri></author><category term="types"/><category term="rpc"/><category term="dx"/><summary type="text">Your service method has a signature. The message that arrives has none — it is JSON, and JSON does not remember what it was supposed to be. This is the story of the bug that leaves no stack trace, why your compiler was never in a position to catch it, and how to put a real check at the boundary without slowing anything down.</summary>
  </entry><entry>
    <title>Autoscale on queue depth, not CPU</title>
    <link href="https://imqueue.org/blog/autoscaling-nodejs-services-on-queue-depth/"/>
    <id>https://imqueue.org/blog/autoscaling-nodejs-services-on-queue-depth/</id>
    <published>2026-08-22T00:00:00Z</published>
    <updated>2026-08-22T00:00:00Z</updated><author><name>Mykhailo Stadnyk</name><uri>https://imqueue.org/blog/authors/mykhailo-stadnyk/</uri></author><category term="queue"/><category term="architecture"/><category term="performance"/><category term="resilience"/><summary type="text">CPU tells you a process is busy, not whether anyone is waiting. An @imqueue service&#39;s backlog is a Redis list, so KEDA can scale on it with no exporter, no Prometheus and no code change — and the metrics server covers the case where you need more.</summary>
  </entry><entry>
    <title>Nothing threw, and the job never ran: silent failures in a Node.js message queue</title>
    <link href="https://imqueue.org/blog/silent-failures-nodejs-message-queue/"/>
    <id>https://imqueue.org/blog/silent-failures-nodejs-message-queue/</id>
    <published>2026-08-21T00:00:00Z</published>
    <updated>2026-08-21T00:00:00Z</updated><author><name>Andrii Glushko</name><uri>https://imqueue.org/blog/authors/andrii/</uri></author><category term="observability"/><category term="resilience"/><category term="delivery"/><category term="jobs"/><summary type="text">A send() that resolves with a message id nobody will ever deliver. A push() that returns cleanly onto a queue redis refused to write. Neither throws, and neither can — the caller has already moved on by the time redis answers. That silence is over: here is what each of those failures now writes to the log instead, and the one upgrade note that costs you a stack trace.</summary>
  </entry><entry>
    <title>Cache invalidation across services: a TTL, a tag, or the database</title>
    <link href="https://imqueue.org/blog/cache-invalidation-nodejs-microservices/"/>
    <id>https://imqueue.org/blog/cache-invalidation-nodejs-microservices/</id>
    <published>2026-08-18T00:00:00Z</published>
    <updated>2026-08-18T00:00:00Z</updated><author><name>Mykhailo Stadnyk</name><uri>https://imqueue.org/blog/authors/mykhailo-stadnyk/</uri></author><category term="cache"/><category term="performance"/><category term="rpc"/><category term="patterns"/><summary type="text">Caching a service method is one decorator. Deciding when the entry dies is the whole job. Here are the three mechanisms measured — a guessed TTL, a tag invalidated by an event, and PostgreSQL dropping the entry 6ms after the row changes — plus the four ways a cache goes on serving data it already knows is stale, and a fifth that got fixed while this was being written.</summary>
  </entry><entry>
    <title>The N+1 problem when GraphQL resolvers call microservices</title>
    <link href="https://imqueue.org/blog/graphql-n-plus-1-microservices/"/>
    <id>https://imqueue.org/blog/graphql-n-plus-1-microservices/</id>
    <published>2026-08-14T00:00:00Z</published>
    <updated>2026-08-14T00:00:00Z</updated><author><name>Andrii Glushko</name><uri>https://imqueue.org/blog/authors/andrii/</uri></author><category term="graphql"/><category term="rpc"/><category term="patterns"/><category term="performance"/><summary type="text">A field resolver runs once per parent object. Put a service call inside it and one innocent-looking query becomes twenty-six. Here is the same query measured at 26 calls and at 3, why your latency chart will not show you the difference, and the two ways the fix comes back silently empty.</summary>
  </entry><entry>
    <title>Distributed tracing for Node.js services over a message queue</title>
    <link href="https://imqueue.org/blog/distributed-tracing-nodejs-message-queue/"/>
    <id>https://imqueue.org/blog/distributed-tracing-nodejs-message-queue/</id>
    <published>2026-08-13T00:00:00Z</published>
    <updated>2026-08-13T00:00:00Z</updated><author><name>Serhiy Morenko</name><uri>https://imqueue.org/blog/authors/serhiy-morenko/</uri></author><category term="observability"/><category term="rpc"/><category term="queue"/><category term="patterns"/><summary type="text">The standard objection to queue-based RPC is that you lose the trace: the caller sends, something else picks it up, and the connection between them is gone. It isn&#39;t — the trace context rides in the request metadata. Here is a measured three-process trace, and the four ways it silently comes out wrong.</summary>
  </entry><entry>
    <title>@imqueue vs NATS: a framework and a transport are not the same choice</title>
    <link href="https://imqueue.org/blog/imqueue-vs-nats/"/>
    <id>https://imqueue.org/blog/imqueue-vs-nats/</id>
    <published>2026-08-03T00:00:00Z</published>
    <updated>2026-08-03T00:00:00Z</updated><author><name>Andrii Glushko</name><uri>https://imqueue.org/blog/authors/andrii/</uri></author><category term="comparison"/><category term="transport"/><category term="rpc"/><category term="architecture"/><category term="delivery"/><summary type="text">NATS is a messaging system; @imqueue is an RPC framework that happens to use one. Comparing them means deciding how much of the contract you want to write yourself — and whether your fleet is Node-only.</summary>
  </entry><entry>
    <title>How Node.js services talk to each other in 2026: the honest options</title>
    <link href="https://imqueue.org/blog/nodejs-service-communication-options-2026/"/>
    <id>https://imqueue.org/blog/nodejs-service-communication-options-2026/</id>
    <published>2026-08-03T00:00:00Z</published>
    <updated>2026-08-03T00:00:00Z</updated><author><name>Mykhailo Stadnyk</name><uri>https://imqueue.org/blog/authors/mykhailo-stadnyk/</uri></author><category term="architecture"/><category term="comparison"/><category term="rpc"/><category term="transport"/><category term="types"/><summary type="text">REST, gRPC, tRPC, NATS, a framework like NestJS or Moleculer, or RPC over a message queue. Six real approaches, what each one costs, and the two questions that actually decide it — including when @imqueue is the wrong answer.</summary>
  </entry><entry>
    <title>One notification, every replica: the LISTEN/NOTIFY duplicate problem</title>
    <link href="https://imqueue.org/blog/postgres-notify-duplicate-listeners/"/>
    <id>https://imqueue.org/blog/postgres-notify-duplicate-listeners/</id>
    <published>2026-07-31T00:00:00Z</published>
    <updated>2026-07-31T00:00:00Z</updated><author><name>Serhiy Morenko</name><uri>https://imqueue.org/blog/authors/serhiy-morenko/</uri></author><category term="patterns"/><category term="resilience"/><category term="delivery"/><summary type="text">LISTEN/NOTIFY is a broadcast, not a queue. Scale a Node app to three replicas and the same notification gets handled three times — no error, no warning, three charges on the card. Here&#39;s why, and what an inter-process lock actually does about it.</summary>
  </entry><entry>
    <title>Graceful shutdown and zero-drop deploys</title>
    <link href="https://imqueue.org/blog/graceful-shutdown-zero-drop-deploys/"/>
    <id>https://imqueue.org/blog/graceful-shutdown-zero-drop-deploys/</id>
    <published>2026-07-28T00:00:00Z</published>
    <updated>2026-07-28T00:00:00Z</updated><author><name>Andrii Glushko</name><uri>https://imqueue.org/blog/authors/andrii/</uri></author><category term="resilience"/><category term="queue"/><category term="patterns"/><summary type="text">Every deploy sends a kill signal to a process that is probably in the middle of something. Nothing 500s, no dashboard turns red, and the work is gone anyway. Here&#39;s what actually happens to an in-flight message on SIGTERM, and the built-in drain that keeps it.</summary>
  </entry><entry>
    <title>Delayed and scheduled work without adding a job system</title>
    <link href="https://imqueue.org/blog/scheduled-work-without-a-job-system/"/>
    <id>https://imqueue.org/blog/scheduled-work-without-a-job-system/</id>
    <published>2026-07-25T00:00:00Z</published>
    <updated>2026-07-25T00:00:00Z</updated><author><name>Mykhailo Stadnyk</name><uri>https://imqueue.org/blog/authors/mykhailo-stadnyk/</uri></author><category term="jobs"/><category term="delivery"/><category term="queue"/><summary type="text">&#34;Send that email in 24 hours&#34; usually turns into a second deployment, a second data model, and a job record shadowing a service method you already wrote. Often the message queue you already run can just do it. Here&#39;s how deferral works as a parameter, and what it costs.</summary>
  </entry><entry>
    <title>Auto-scaling Redis broker: with and without broadcast</title>
    <link href="https://imqueue.org/blog/horizontally-scalable-redis-broker/"/>
    <id>https://imqueue.org/blog/horizontally-scalable-redis-broker/</id>
    <published>2026-07-24T00:00:00Z</published>
    <updated>2026-07-24T00:00:00Z</updated><author><name>Serhiy Morenko</name><uri>https://imqueue.org/blog/authors/serhiy-morenko/</uri></author><category term="discovery"/><category term="queue"/><category term="architecture"/><category term="patterns"/><summary type="text">One Redis behind your message bus is a ceiling and a single point of failure. The promoter and unicaster modules turn a fleet of plain Redis instances into a horizontally auto-scaling broker — here are the recipes for networks that deliver broadcast and for clouds like GCP that don&#39;t, and how to encrypt the result when the brokers announce addresses no certificate can carry.</summary>
  </entry><entry>
    <title>One isolated imq CLI home per @imqueue project</title>
    <link href="https://imqueue.org/blog/isolated-imq-cli-environments/"/>
    <id>https://imqueue.org/blog/isolated-imq-cli-environments/</id>
    <published>2026-07-23T00:00:00Z</published>
    <updated>2026-07-23T00:00:00Z</updated><author><name>Andrii Glushko</name><uri>https://imqueue.org/blog/authors/andrii/</uri></author><category term="tooling"/><category term="dx"/><category term="patterns"/><summary type="text">Every imq invocation shares one ~/.imq — one config, one pid registry, one set of logs. Here&#39;s how to give each project its own isolated CLI environment with IMQ_CLI_HOME, plus recipes for direnv, shell wrappers, per-client tokens and disposable sandboxes.</summary>
  </entry><entry>
    <title>RPC over Redis in Node.js: patterns and pitfalls</title>
    <link href="https://imqueue.org/blog/rpc-over-redis-nodejs/"/>
    <id>https://imqueue.org/blog/rpc-over-redis-nodejs/</id>
    <published>2026-07-23T00:00:00Z</published>
    <updated>2026-07-23T00:00:00Z</updated><author><name>Serhiy Morenko</name><uri>https://imqueue.org/blog/authors/serhiy-morenko/</uri></author><category term="rpc"/><category term="queue"/><category term="transport"/><category term="patterns"/><summary type="text">How request/reply RPC over Redis actually works in Node.js — correlation, timeouts and at-least-once delivery, which of those @imqueue handles for you, and what it deliberately leaves to you: retrying a failed RPC call, coalescing duplicate concurrent calls with @lock, and the circuit breaker it does not ship.</summary>
  </entry><entry>
    <title>BullMQ alternatives for Node.js: an honest 2026 guide</title>
    <link href="https://imqueue.org/blog/bullmq-alternatives/"/>
    <id>https://imqueue.org/blog/bullmq-alternatives/</id>
    <published>2026-07-22T00:00:00Z</published>
    <updated>2026-07-22T00:00:00Z</updated><author><name>Mykhailo Stadnyk</name><uri>https://imqueue.org/blog/authors/mykhailo-stadnyk/</uri></author><category term="comparison"/><category term="queue"/><category term="jobs"/><summary type="text">BullMQ is the default Redis job queue for Node.js — but it isn&#39;t the only choice. Here&#39;s an even-handed map of the alternatives (Bee-Queue, pg-boss, Agenda, @imqueue/job and more), what each is actually good at, and how to pick.</summary>
  </entry><entry>
    <title>RPC between Node.js microservices over a message queue</title>
    <link href="https://imqueue.org/blog/rpc-over-message-queue-nodejs/"/>
    <id>https://imqueue.org/blog/rpc-over-message-queue-nodejs/</id>
    <published>2026-07-22T00:00:00Z</published>
    <updated>2026-07-22T00:00:00Z</updated><author><name>Mykhailo Stadnyk</name><uri>https://imqueue.org/blog/authors/mykhailo-stadnyk/</uri></author><category term="rpc"/><category term="queue"/><category term="architecture"/><summary type="text">Why route internal service-to-service calls through a message queue instead of HTTP or gRPC — and how @imqueue makes those calls fully typed with zero client boilerplate.</summary>
  </entry>
</feed>
