Skip to content

jackline-kaunda/auto_bill

Repository files navigation

Building a Simple Billing System with GenServer

This project demonstrates how to build a lightweight billing system using Elixir and GenServer. It shows how to process payments, manage recurring billing cycles, and use Elixir’s concurrency model to schedule future tasks. The example is based on a session by Jackline Wayua and Achieng’ Linda.


Overview

Billing systems usually need to do a few things well:

  • Accept a payment request
  • Run billing logic reliably
  • Store or update state
  • Charge again next month without manual triggers

GenServer gives you an elegant way to handle these tasks because it lets you create long-running processes that hold state, respond to messages, and schedule future work.

This project shows how to use a single GenServer to automate monthly billing using GenServer.call/3 and Process.send_after/3.


Features

  • A GenServer that processes payments through a :pay call
  • Automatically schedules the next month’s billing cycle
  • Simple state management inside the GenServer
  • Uses Process.send_after/3 for recurring tasks
  • Beginner-friendly starting point for subscription systems
  • Easy to extend with real payment APIs or persistence

How It Works

1. Client Interaction

A simple client function triggers payment processing:

def process_payment(pid) do
  GenServer.call(pid, :pay)
end

This sends a synchronous request to the GenServer asking it to process a payment.


2. GenServer Handling

Inside the GenServer:

@impl true
def handle_call(:pay, _from, attrs) do
  response = server_process_payment(attrs)
  schedule_next_monthly_payment()
  {:reply, response, attrs}
end

The GenServer:

  1. Processes the payment
  2. Calculates when the next payment should occur
  3. Schedules a message to itself for that future date
  4. Returns the result

3. Scheduling Recurring Billing

Recurring payments are managed using Process.send_after/3:

def schedule_next_monthly_payment do
  next_payment_time = calculate_next_month_in_milliseconds()
  Process.send_after(self(), :next_pay, next_payment_time)
end

This ensures the GenServer wakes itself up a month later to perform the same billing operation again.


When to Use This Approach

GenServer billing works well when:

  • You need background workers that run on a schedule
  • You want predictable recurring billing
  • You are managing state within a single process
  • You’re building subscription-based features
  • You want a simple prototype before integrating full payment services

For production systems, you can extend this with:

  • Database storage
  • Error handling and retries
  • Supervision trees
  • Real payment APIs (M-Pesa, Stripe, PayPal, etc.)

Project Structure

/lib
  billing/
    billing_server.ex   # The GenServer implementation

/test
  billing_server_test.exs # Optional tests

mix.exs                # Project dependencies
README.md              # Documentation

Running the Project

Clone the repo:

git clone <your-repo-url>
cd <repo-folder>

Install dependencies:

mix deps.get

Run an interactive Elixir shell:

iex -S mix

Start the GenServer:

{:ok, pid} = BillingServer.start_link(%{user: "Demo User"})
BillingServer.process_payment(pid)

Extending the System

Here are a few simple ways to grow the project:

  • Add a real payment module with API integrations
  • Store transaction history in a database
  • Use Phoenix LiveView to build a dashboard
  • Handle failed payments or retries
  • Support multiple users with a Registry or Dynamic Supervisor

Why GenServer?

GenServer is perfect for this kind of problem because it gives you:

  • A process to hold billing state
  • A predictable lifecycle
  • Built-in message handling
  • Easy scheduling
  • Clear concurrency semantics

It’s a great introduction to building real-world background processes in Elixir.


Contributing

Feel free to open issues, submit pull requests, or suggest improvements.


About

A simple billing system

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •