Current section
Files
Jump to
Current section
Files
examples/02_pagination_with_single_operation.exs
defmodule Examples.PaginationWithSingleOperation do
@moduledoc """
Using single operation for pagination/cycling through data.
This example demonstrates how to use single_operation to paginate through
records, checking health between each page. This is useful when you want
full control over the pagination logic.
"""
use AdaptiveBackfill
# Paginate through users with health checks between pages
single_operation :paginate_users do
mode :sync
health_checks [&check_database_health/0, &check_memory_usage/0]
handle fn health_check ->
# Start pagination from offset 0
paginate_recursive(0, 50, health_check)
end
on_complete fn result ->
case result do
{:ok, total_processed} ->
IO.puts("✓ Successfully processed #{total_processed} users")
{:halt, reason, processed} ->
IO.puts("✗ Halted after processing #{processed} users: #{inspect(reason)}")
end
end
end
# Recursive pagination function
defp paginate_recursive(offset, limit, health_check, total_processed \\ 0) do
IO.puts("\n--- Processing page at offset #{offset} ---")
# Fetch page of users
users = fetch_users_page(offset, limit)
if Enum.empty?(users) do
# No more users, we're done
IO.puts("No more users to process")
{:ok, total_processed}
else
# Process this page
process_users_page(users)
new_total = total_processed + length(users)
# Check health before continuing to next page
case health_check.() do
:ok ->
IO.puts("Health check passed, continuing to next page...")
# Continue to next page
paginate_recursive(offset + limit, limit, health_check, new_total)
{:halt, reason} ->
IO.puts("Health check failed, stopping pagination")
{:halt, reason, new_total}
end
end
end
defp fetch_users_page(offset, limit) do
# Simulate fetching from database
IO.puts(" Fetching users with offset=#{offset}, limit=#{limit}")
:timer.sleep(100)
# Simulate returning users (empty after offset 200)
if offset >= 200 do
[]
else
Enum.map(1..limit, fn i ->
%{id: offset + i, email: "user#{offset + i}@example.com"}
end)
end
end
defp process_users_page(users) do
IO.puts(" Processing #{length(users)} users...")
Enum.each(users, fn user ->
# Simulate processing each user
IO.puts(" - Processing user #{user.id}: #{user.email}")
end)
:timer.sleep(200)
end
defp check_database_health do
# Simulate database health check
active_connections = :rand.uniform(100)
if active_connections > 80 do
{:halt, "Too many database connections: #{active_connections}"}
else
IO.puts(" ✓ Database health OK (#{active_connections} connections)")
:ok
end
end
defp check_memory_usage do
# Simulate memory check
memory_mb = :rand.uniform(1000)
if memory_mb > 900 do
{:halt, "Memory usage too high: #{memory_mb}MB"}
else
IO.puts(" ✓ Memory usage OK (#{memory_mb}MB)")
:ok
end
end
end
# Run the example
# Examples.PaginationWithSingleOperation.paginate_users()