Introducing the Cloud Reaper for Azure

Introducing the Cloud Reaper for Azure

A few years ago, while I was studying C# development, I wanted to build something real... not just another classroom exercise, but a project that actually solved a problem I had. I've always been fascinated by serverless tech on Azure, especially Azure Functions and the Durable Task Framework. The concept of Durable Entities as long-lived, stateful objects orchestrated by the runtime, absolutely hooked me. It was quite clunky back in the days, but I genuinely enjoyed figuring it out and building the first version of what would become Cloud Reaper for Azure.

Fun fact: the very first commit on this repo landed on December 31st, 2021, right before I headed out to celebrate New Year's Eve with my friends. Not a bad way to close out the year.

ℹ️
Note: I won't go into detailed setup or deployment steps in this post. All the technical documentation lives directly in the GitHub repository, so head over there if you want to get your hands dirty.

Introduction

Cloud Reaper for Azure is an open-source Azure Functions based engine that automatically deletes resource groups after a defined lifetime. You tag a resource group with a CloudReaperLifetime value in minutes, and Cloud Reaper takes care of the rest. Confirming the schedule, stamping the deletion time, and cleaning up when the clock runs out.

The problem it solves is one I'm sure many of you know: you spin up a resource group for a demo, a workshop, or a quick proof of concept. You tell yourself you'll clean it up later. And then you don't. A few weeks go by, and suddenly your subscription is full of forgotten resources quietly burning through your budget.

Cloud Reaper removes that mental overhead entirely. Tag it, forget it, move on.

ℹ️
The original idea was inspired by Jeff Holan's functions-csharp-entities-grimreaper. I loved the concept, but I wanted to rebuild it from scratch to fit my exact use case, my stack, and my way of doing things.

Purpose

I wanted Cloud Reaper to be fully event-driven from the start. No scheduled polling, no periodic scans across your subscription. Instead, it listens for Azure Event Grid events. Specifically, Microsoft.Resources.ResourceWriteSuccess and reacts the moment a tagged resource group is created or updated. That keeps it lightweight and responsive.

I've been running this solution across all my demo, test, and dev environments for years now. As a Cloud Architect, I constantly deploy resources to demonstrate something to a customer or test a new configuration. Cloud Reaper gives me what I like to call headless mode. I deploy what I need, set a lifetime tag, and never think about it again. No reminders, no cleanup scripts, no surprise invoices at the end of the month.


Technology

Cloud Reaper is built on a few core Azure building blocks.

Azure Functions

Azure Functions is Azure's serverless compute platform. You write focused pieces of code, the platform handles scaling and execution, and you only pay for what runs. Cloud Reaper uses the isolated worker model on .NET 10, which gives me full control over dependencies and middleware.

I really love Azure Functions and preferr them way over Azure Automation Accounts because of it's local development experience and it's deep integration into the Azure ecosystem. You can develop Azure Functions in C#, PowerShell and many more languages.

Azure Functions documentation
Azure Functions is a managed platform-as-a-service (PaaS) provider that provides event-driven and scheduled compute resources for Azure cloud services. You can focus on the code that matters most to you and Functions handles the rest. Functions can provide scalable and serverless hosting for your code projects written in the most productive language for you. You can use Functions to build web APIs, respond to database changes, process IoT streams, manage message queues, and more.

Durable Task Framework & Durable Entities

The Durable Task Framework extends Azure Functions with stateful orchestration. Instead of fire-and-forget functions, you get long-running workflows that can wait, retry, and coordinate across multiple steps.

Durable Entities build on top of that. They're long-lived, addressable objects that hold state and respond to operations. Think of them as lightweight actors. In Cloud Reaper, each tracked resource group is represented by its own durable entity that manages the full lifecycle: storing metadata, scheduling the deletion timer, and triggering the cleanup.

Durable Functions overview - Azure Durable
Learn how Durable Functions extends Azure Functions to build reliable, stateful workflows in a serverless environment.

Azure Event Grid

Event Grid is Azure's managed event routing service. It connects event sources to handlers in a publish-subscribe model with built-in retry logic. Cloud Reaper subscribes to Microsoft.Resources.ResourceWriteSuccess events at the subscription level. Every time a resource group is created or updated, Event Grid fires an event and Cloud Reaper picks it up. This is what makes the whole solution event-driven.

Azure Event Grid documentation
Learn how to use Azure Event Grid to react to relevant events across both Azure and non-Azure services in near-real time fashion.

How it works

Using Cloud Reaper is straightforward. The entire workflow is driven by tags on your resource groups.

When you create a resource group that you want Cloud Reaper to manage, add a CloudReaperLifetime tag with a value in minutes. For example, a value of 60 means the resource group will be deleted one hour after Cloud Reaper picks it up. As an alternative you just can simply apply that tag to an existing resource group.

Once Event Grid delivers the creation event, Cloud Reaper validates the tag and schedules the deletion. It then applies two additional tags to the resource group: CloudReaperStatus is set to Confirmed, letting you know the resource group has been registered. CloudReaperDeletionTime contains the exact UTC timestamp (ISO 8601) of when the deletion will happen.

When the timer runs out, Cloud Reaper deletes the resource group and everything inside it. No confirmation prompts, no manual steps. That's the whole point.

If you change your mind and want to keep a resource group alive, simply remove the CloudReaperLifetime tag. Cloud Reaper will detect the change and unschedule the deletion. For resource groups that should never be touched in the first place, apply a delete lock to protect them.

⚠️
Cloud Reaper has permission to delete any resource group in the target subscription. Only deploy it to dev, test, or demo environments. If you want to protect specific resource groups, apply a delete lock.

Whats new

Version 2.0.0 is a complete rewrite of the original codebase. The old version served me well, but it was built on the legacy in-process hosting model and had outgrown its architecture. So I started from scratch.

Here's what changed:

  • Isolated worker model. Cloud Reaper now runs on .NET 10 with the Azure Functions isolated worker model, giving full control over the runtime and dependencies.
  • One-command deployment. The entire infrastructure and app deployment is handled by a single azd up. No manual steps, no portal clicking.
  • Improved documentation. Both the deployment guide and the local development setup have been rewritten from scratch with clear prerequisites and step-by-step instructions.
  • Better error handling. The function code is now much more resilient, with proper validation, logging, and graceful handling of edge cases like missing or invalid tags.
  • New tags. Cloud Reaper now applies a CloudReaperDeletionTime tag showing the exact scheduled deletion timestamp, in addition to the existing CloudReaperStatus tag.
  • Cancellation support. Removing the CloudReaperLifetime tag from a resource group now properly unschedules the deletion, something the old version didn't handle cleanly.

Wrap up

Cloud Reaper for Azure has been my sidekick for years now, quietly cleaning up after my demos and experiments so I don't have to. The v2.0.0 rewrite brings it up to modern standards with .NET 10, the isolated worker model, and a proper deployment story with azd and Terraform.

If you want to dive into the technical details, deploy it to your own subscription, or contribute to the project, check out the GitHub repository. Everything you need is documented there.

And remember: friends don't let friends forget about running resource groups. But if they do, Cloud Reaper has their back.

Member discussion