<?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>Forem: Rahul Bhati</title>
    <description>The latest articles on Forem by Rahul Bhati (@therahulbhati).</description>
    <link>https://forem.com/therahulbhati</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F414189%2Fdb3202b4-7929-41dc-a9d5-c964f2b6e9a8.jpeg</url>
      <title>Forem: Rahul Bhati</title>
      <link>https://forem.com/therahulbhati</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/therahulbhati"/>
    <language>en</language>
    <item>
      <title>Delay Queues: Do It Later, Reliably</title>
      <dc:creator>Rahul Bhati</dc:creator>
      <pubDate>Tue, 21 Oct 2025 17:52:31 +0000</pubDate>
      <link>https://forem.com/therahulbhati/delay-queues-do-it-later-reliably-42kc</link>
      <guid>https://forem.com/therahulbhati/delay-queues-do-it-later-reliably-42kc</guid>
      <description>&lt;h2&gt;
  
  
  What is a delay queue?
&lt;/h2&gt;

&lt;p&gt;A delay queue holds a message/job until a specified delay time in the future, then makes it available for processing. It's the simplest way to schedule "do this later" without blocking workers or rolling your own cron logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use a delay queue?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Retries with backoff&lt;/strong&gt; — retry failed tasks after a delay.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduled tasks&lt;/strong&gt; — run at specific times (e.g., reminder emails).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate smoothing&lt;/strong&gt; — spread out work to avoid thundering herds.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to choose what
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Broker-based Delay Queues
&lt;/h3&gt;

&lt;p&gt;Built-in support for delayed messages in brokers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloud-managed&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS SQS&lt;/strong&gt; (&lt;code&gt;DelaySeconds&lt;/code&gt;, per-message up to 15 min)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure Service Bus&lt;/strong&gt; (scheduled messages)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Cloud Tasks&lt;/strong&gt; (scheduled delivery)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Open-source&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Apache Pulsar&lt;/strong&gt; (delayed messages)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RabbitMQ&lt;/strong&gt; (delayed-message plugin)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best for&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static/simple delays
&lt;/li&gt;
&lt;li&gt;Operational simplicity over flexibility
&lt;/li&gt;
&lt;li&gt;Delay ranges: seconds → hours &lt;em&gt;(SQS: 15 min/message; Service Bus/Pulsar: much longer)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tradeoffs&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limited introspection: hard to list/search/cancel/reschedule after enqueue
&lt;/li&gt;
&lt;li&gt;Cloud-managed = zero ops but vendor lock-in
&lt;/li&gt;
&lt;li&gt;Open-source = portable but you run the infra &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Redis ZSET Scheduler
&lt;/h3&gt;

&lt;p&gt;Use a Redis &lt;strong&gt;sorted set&lt;/strong&gt; with score = execution timestamp. Fast lookups; easy cancel/reschedule.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High-throughput scheduling (10K+ jobs/sec)
&lt;/li&gt;
&lt;li&gt;Cancellable delays &amp;amp; "list upcoming jobs" APIs
&lt;/li&gt;
&lt;li&gt;Dynamic rescheduling (snooze/postpone)
&lt;/li&gt;
&lt;li&gt;Sub-second granularity &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&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;# Schedule a job&lt;/span&gt;
ZADD delays &amp;lt;execution_timestamp&amp;gt; &amp;lt;job_id&amp;gt;

&lt;span class="c"&gt;# Fetch due jobs (batch of 100)&lt;/span&gt;
ZRANGEBYSCORE delays &lt;span class="nt"&gt;-inf&lt;/span&gt; &amp;lt;now&amp;gt; LIMIT 0 100

&lt;span class="c"&gt;# Remove once picked up&lt;/span&gt;
ZREM delays &amp;lt;job_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Tradeoffs&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single point of failure unless Redis is clustered or replicated.&lt;/li&gt;
&lt;li&gt;In-memory volatility: Data can be lost on crash if AOF/RDB not configured properly.&lt;/li&gt;
&lt;li&gt;External Execution Required: Redis only tracks when to run jobs — execution must be handled by polling workers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Postgres + SKIP LOCKED
&lt;/h3&gt;

&lt;p&gt;Store jobs in your main database. Poll with &lt;code&gt;FOR UPDATE SKIP LOCKED&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;Best for&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Atomic job scheduling + business logic ("cancel order and schedule refund" in one DB transaction)&lt;/li&gt;
&lt;li&gt;Teams already using Postgres — no new infrastructure.&lt;/li&gt;
&lt;li&gt;Strong consistency and strict ordering requirements.&lt;/li&gt;
&lt;li&gt;Moderate throughput workloads (&amp;lt;10K jobs/sec).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;run_at&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'pending'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;run_at&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;SKIP&lt;/span&gt; &lt;span class="n"&gt;LOCKED&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why &lt;code&gt;SKIP LOCKED&lt;/code&gt;?&lt;/strong&gt;&lt;br&gt;
Multiple workers poll concurrently without lock contention. Each grabs a batch, skips locked rows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tradeoffs&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Polling interval creates latency floor (5s poll = up to 5s jitter).&lt;/li&gt;
&lt;li&gt;Index pressure on high churn.&lt;/li&gt;
&lt;li&gt;Not for sub-second precision.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  4. DynamoDB TTL
&lt;/h3&gt;

&lt;p&gt;AWS-native approach using DynamoDB's Time To Live (TTL) feature combined with DynamoDB Streams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best for&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serverless architectures on AWS.&lt;/li&gt;
&lt;li&gt;Long delays (hours to days).&lt;/li&gt;
&lt;li&gt;Variable/unpredictable load patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Implementation&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Schedule item with TTL&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;putItem&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;delayed_jobs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;job_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;order-123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;delay_seconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* job data */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Lambda triggered by DynamoDB Streams on deletion&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Tradeoffs&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TTL deletion is eventually consistent (typically within 48 hours, but usually minutes)&lt;/li&gt;
&lt;li&gt;Not suitable for precise timing needs.&lt;/li&gt;
&lt;li&gt;AWS lock-in.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Timer Wheels / Bucketed Timers
&lt;/h3&gt;

&lt;p&gt;An in-memory data structure optimized for millions of delays per second.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Netty’s HashedWheelTimer&lt;/li&gt;
&lt;li&gt;Kafka broker request purgatory (hierarchical timing wheels) &lt;a href="https://www.confluent.io/blog/kafka-internals-request-purgatory/" rel="noopener noreferrer"&gt;reference&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best for&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Session timeouts (30-sec idle = disconnect)&lt;/li&gt;
&lt;li&gt;Rate limiter token bucket refills&lt;/li&gt;
&lt;li&gt;Game server tick-based events&lt;/li&gt;
&lt;li&gt;Short delays (&amp;lt;1 hour), acceptable precision ~100ms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it's fast?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O(1) insertions using a circular wheel of buckets&lt;/li&gt;
&lt;li&gt;Batched execution of timers in the same bucket&lt;/li&gt;
&lt;li&gt;Trades precision for throughput.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tradeoffs&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In-memory only(not durable)&lt;/li&gt;
&lt;li&gt;Perfect for ephemeral delays where loss is acceptable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Workflow Engines
&lt;/h3&gt;

&lt;p&gt;Full orchestration engines with built-in delay scheduling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Temporal&lt;/li&gt;
&lt;li&gt;Camunda&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Best for&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-step processes with delays between steps (e.g., Abandoned cart: 1h idle → +2h reminder → +24h reminder (+incentive) → close.).&lt;/li&gt;
&lt;li&gt;Human approval steps with timeouts&lt;/li&gt;
&lt;li&gt;Microservice orchestration with retries and delays&lt;/li&gt;
&lt;li&gt;Audit trails and visual workflow editors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tradeoffs&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heavy infrastructure and operational complexity.&lt;/li&gt;
&lt;li&gt;Overkill for simple delay needs, but perfect when delays are part of larger state workflows.&lt;/li&gt;
&lt;li&gt;Steep learning curve&lt;/li&gt;
&lt;li&gt;Resource-intensive (separate database, workers, UI)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Delivery Semantics &amp;amp; Idempotency
&lt;/h2&gt;

&lt;p&gt;Most delay queue implementations provide &lt;strong&gt;at-least-once&lt;/strong&gt; delivery guarantees. This means jobs may be delivered multiple times due to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Worker crashes before acknowledging&lt;/li&gt;
&lt;li&gt;Network timeouts during acknowledgment&lt;/li&gt;
&lt;li&gt;Duplicate scheduling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Design for Idempotency&lt;/strong&gt;&lt;br&gt;
Your job handlers should be safe to retry. Use unique job IDs, database constraints, or distributed locks to ensure processing a job multiple times has no adverse effects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exactly-once Delivery&lt;/strong&gt;&lt;br&gt;
Kafka (with transactions) and Pulsar (with deduplication) can provide stronger guarantees, but at the cost of complexity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dead Letter Queues (DLQs)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most delay queue systems support DLQs to isolate jobs that permanently fail after exhausting retries&lt;/li&gt;
&lt;li&gt;When a job fails repeatedly (e.g., 3-5 attempts with exponential backoff), it's moved to the DLQ for manual inspection&lt;/li&gt;
&lt;li&gt;Prevents poisonous messages from blocking healthy jobs&lt;/li&gt;
&lt;li&gt;DLQ growth indicates systematic issues like bad code deploys, external service outages, or malformed data&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Observability
&lt;/h2&gt;

&lt;p&gt;Regardless of the delay queue you choose, implement monitoring and alerting for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Queue depth&lt;/strong&gt;: Number of pending jobs (alert on unexpected growth)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lag&lt;/strong&gt;: Time between scheduled and actual execution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Throughput&lt;/strong&gt;: Jobs processed per second&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failure rates&lt;/strong&gt;: Percentage of jobs that fail and require retries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Age of oldest job&lt;/strong&gt;: Detect stuck/stale jobs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dead letter queue (DLQ) depth&lt;/strong&gt;: Jobs that exceeded retry limits&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Decision Matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Your constraint&lt;/th&gt;
&lt;th&gt;Go with&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fully managed (AWS)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;SQS&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fully managed (GCP)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Cloud Tasks&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fully managed (Azure)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Service Bus&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fully managed, avoid vendor lock-in&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Managed Pulsar&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Need speed + easy cancellation/inspect&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Redis ZSET&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Need transactional consistency&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Postgres + SKIP LOCKED&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serverless AWS + long delays&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;DynamoDB TTL&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Short-lived delays, loss acceptable&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Timer wheels&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100K+ delays/sec, ephemeral OK&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Timer wheels&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-step workflows with state&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Temporal / Camunda&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Choose based on your requirements: cloud-managed for simplicity, Redis/Postgres for speed and control, workflow engines for complex orchestration. The best delay queue fits your existing stack and operational maturity.&lt;/p&gt;

&lt;p&gt;Don't build your own delay queue. Use an existing solution unless you have very specific requirements that nothing else can satisfy.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>postgres</category>
      <category>redis</category>
      <category>systemdesign</category>
    </item>
  </channel>
</rss>
