### Start Minikube with Specific Kubernetes Version and Resources Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/kubernetes/readme.md This command starts a Minikube cluster with a specified Kubernetes version, driver, memory, CPU allocation, and enables the registry addon with embedded certificates. Ensure Docker Desktop is installed and configured with sufficient resources before running. ```bash minikube start --kubernetes-version="v1.26.5" --driver="docker" --memory="15G" --cpus="6" --addons="registry" --embed-certs="true" ``` -------------------------------- ### Install Docker on EC2 Instance Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/AWSUsageInstructions.md Installs the latest Docker Engine package and starts the Docker service. Adds the current user to the docker group for sudo-less execution. Tests the installation with a hello-world container. ```sh $ curl -fsSL https://get.docker.com -o get-docker.sh $ sh get-docker.sh ``` ```sh sudo service docker start ``` ```sh sudo usermod -a -G docker ubuntu ``` ```sh docker run hello-world ``` -------------------------------- ### Start Minikube and Connect to Admin Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Initiates the Minikube environment and establishes a connection to the cluster's admin interface. ```bash ./minikube-run.sh ./k8s_connect_admin.sh ``` -------------------------------- ### Start Services and Create Auction (Bash) Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Starts all Docker services and uses the Admin interface to create an initial auction. Ensure the 'docker' directory is the current working directory. ```bash docker compose up -d docker exec -i aeron-admin1-1 java -jar admin-uber.jar ``` -------------------------------- ### Build and Run Aeron IO Admin Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/admin/readme.md Commands to build the project and start a single-node cluster, followed by instructions to run the admin tool and connect to the cluster. ```bash ./gradlew build ./gradlew :cluster:run ``` ```bash java -jar admin/build/libs/admin-uber.jar ``` ```bash connect ``` -------------------------------- ### Launch Clustered Service with Configuration Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Bootstraps a ClusteredMediaDriver and ClusteredServiceContainer. Configuration can be set via environment variables or system properties. This example shows manual configuration for a three-node cluster, including setting ingress channels and leader heartbeat timeouts. ```java // Configuration is read from environment variables or system properties: // CLUSTER_PORT_BASE / -Dport.base (default: 9000) // CLUSTER_NODE / -Dnode.id (default: 0) // CLUSTER_ADDRESSES / -Dcluster.addresses (default: "localhost") // BASE_DIR (default: ./node) // DNS_DELAY (set to "true" to wait 5s before DNS resolution) // Three-node cluster launched via Docker Compose (see docker/docker-compose.yml): // node0: CLUSTER_NODE=0, CLUSTER_ADDRESSES=172.16.202.2,172.16.202.3,172.16.202.4 // node1: CLUSTER_NODE=1, same CLUSTER_ADDRESSES // node2: CLUSTER_NODE=2, same CLUSTER_ADDRESSES // Equivalent to what ClusterApp.main() does internally: List hosts = List.of("172.16.202.2", "172.16.202.3", "172.16.202.4"); ClusterConfig config = ClusterConfig.create(0, hosts, hosts, 9000, new AppClusteredService()); config.consensusModuleContext().ingressChannel("aeron:udp"); config.consensusModuleContext().leaderHeartbeatTimeoutNs(TimeUnit.SECONDS.toNanos(3)); config.baseDir(new File("/home/aeron/jar/aeron-cluster")); try (ShutdownSignalBarrier barrier = new ShutdownSignalBarrier(); ClusteredMediaDriver driver = ClusteredMediaDriver.launch( config.mediaDriverContext().terminationHook(barrier::signalAll), config.archiveContext(), config.consensusModuleContext().terminationHook(barrier::signalAll))); ClusteredServiceContainer container = ClusteredServiceContainer.launch( config.clusteredServiceContext().terminationHook(barrier::signalAll))) { barrier.await(); // blocks until SIGINT/SIGTERM } ``` -------------------------------- ### Add Auction via Admin Interface (Text) Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Example output from the Admin interface after adding an auction. This demonstrates the expected response format. ```text admin > add-auction created-by=500 name=Tulips duration=1800 Auction added with id: 1 New auction: 'Tulips' (1) Auction 1 is now in state OPEN. There have been 0 bids. ``` -------------------------------- ### Create Second Auction (Text) Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Example output from the Admin interface after adding a second auction. This is done to demonstrate replicating cluster log entries following a snapshot. ```text admin > add-auction created-by=500 name=Daffodils duration=1800 Auction added with id: 2 New auction: 'Daffodils' (2) Auction 2 is now in state OPEN. There have been 0 bids. ``` -------------------------------- ### Start Docker Containers Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/docker/readme.md Starts the Aeron cluster and admin containers in detached mode. ```bash docker compose up -d ``` -------------------------------- ### Admin Interface - Auctions Restored (Text) Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Example output from the Admin interface after restoring from backup, showing the previously created auctions. This confirms the restore operation was successful. ```text admin > list-auctions Auction count: 2 Auction 'Tulips' with id 1 created by 500 is now in state PRE_OPEN Auction 'Daffodils' with id 2 created by 500 is now in state OPEN ``` -------------------------------- ### Backup Node Log Output (Text) Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Example log output from the backup node indicating successful retrieval of snapshot data. This confirms that replication is working as expected. ```text Response from Cluster. Log Source Member: 2. Cluster Members: [0. 172.16.202.2:9003 (not leader), 1. 172.16.202.3:9103 (not leader), 2. 172.16.202.4:9203 (leader)]. Snapshots to retrieve: [Snapshot recordingId: 0, Snapshot recordingId: 1] Updating log for recording [recordingId: 2, logPosition: 544, recordingId: 1, logPosition: 544, recordingId: 3, logPosition: -1]. Snapshots retrieved: [Snapshot recordingId: 1, Snapshot recordingId: 2] Reached position 1408 in recording 3 ``` -------------------------------- ### Build and Run Aeron Cluster Locally Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Instructions for building the project and running a single-node cluster and admin REPL. Ensure Java 21 and Gradle 9.4.1 are installed. The cluster node and admin REPL must be run in separate terminals. ```bash # Requirements: Java 21, Gradle 9.4.1, Linux or macOS # 1. Build all modules (outputs cluster-uber.jar and admin-uber.jar) ./gradlew # 2. Start a single-node cluster (node 0, port base 9000, data dir ./node0) ./gradlew :cluster:run # or directly: java -jar cluster/build/libs/cluster-uber.jar # 3. In a separate terminal, start the admin REPL # (must be a real terminal – not IntelliJ or Gradle run) java -jar admin/build/libs/admin-uber.jar # Expected cluster console output: # INFO io.aeron.samples.ClusterApp - Started Cluster Node... # Expected admin REPL output: # ------------------------------------------------- # Welcome to the Aeron Cluster QuickStart Console # ------------------------------------------------- # Not auto-connecting to cluster # admin > ``` -------------------------------- ### Start ClusterInteractionAgent Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Start the ClusterInteractionAgent on a dedicated thread to bridge the admin REPL to AeronCluster. ```java // The agent is started on a dedicated thread: OneToOneRingBuffer adminClusterChannel = new OneToOneRingBuffer(new UnsafeBuffer(...)); ClusterInteractionAgent agent = new ClusterInteractionAgent(adminClusterChannel, idleStrategy, running); AgentRunner runner = new AgentRunner(idleStrategy, Throwable::printStackTrace, null, agent); AgentRunner.startOnThread(runner); ``` -------------------------------- ### Build and Run Docker Compose Cluster Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Builds the Aeron Cluster source code, container images, and starts a three-node cluster with admin and backup nodes. Use this to set up a local development environment. ```bash # From the docker/ directory: # 1. Build the source code first: cd .. ./gradlew cd docker # 2. Build container images: docker compose build # 3. Start the cluster (3 cluster nodes + 2 admin nodes + 1 backup node): docker compose up -d ``` -------------------------------- ### Configure Docker for ECR Credential Helper Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/AWSUsageInstructions.md Installs the Amazon ECR Credential Helper and configures Docker to use it for authentication, enabling image pulls from ECR without explicit `docker login`. ```bash sudo apt install amazon-ecr-credential-helper ``` ```json { "credsStore": "ecr-login" } ``` -------------------------------- ### Create and Manage Auctions with Validation Rules Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Use this to create new auctions, ensuring that start and end times, duration, and participant details meet predefined validation rules. It also handles adding bids with price improvement enforcement. ```java // Validation rules for addAuction: // - startTime must be strictly after current cluster time // - endTime must be after startTime // - duration (endTime - startTime) must be ≥ 20 seconds // - createdByParticipantId must be a known participant // - name and description must be non-null, non-blank // Create an auction (times are epoch milliseconds): long now = System.currentTimeMillis(); auctions.addAuction( 500L, // createdByParticipantId now + 100, // startTime (0.1s from now) now + 25_000, // endTime (25s from now) UUID.randomUUID().toString(), // correlationId "Tulips", // name "Spring flower auction" // description ); // On SUCCESS → schedules 3 timers: open, close, remove // On FAILURE → clusterClientResponder.rejectAddAuction(correlationId, AddAuctionResult.INVALID_START_TIME|...) // Add a bid (price in whole cents; must be a price improvement): auctions.addBid( 1L, // auctionId 501L, // addedByParticipantId (cannot be the auction creator) 1000L, // price in cents (must be > current winning bid, > 0) UUID.randomUUID().toString() ); // On SUCCESS → auction.setWinningBid(); broadcasts AuctionUpdateEvent to all sessions // On FAILURE → clusterClientResponder.rejectAddBid(correlationId, auctionId, AddAuctionBidResult.CANNOT_SELF_BID|...) // Bid rejection codes: AUCTION_NOT_OPEN, UNKNOWN_AUCTION, UNKNOWN_PARTICIPANT, // INVALID_PRICE, PRICE_BELOW_CURRENT_WINNING_BID, CANNOT_SELF_BID // List auctions sorted by ID: List list = auctions.getAuctionList(); Auction a = list.get(0); a.getAuctionId(); // auto-incremented long starting at 1 a.getAuctionStatus(); // AuctionStatus.PRE_OPEN | OPEN | CLOSED a.getCurrentPrice(); // current winning bid in cents a.getBidCount(); // total bids accepted a.getWinningParticipantId(); // -1L if no bids yet // Admin REPL equivalents: // add-auction created-by=500 name=Tulips // add-bid auction-id=1 created-by=501 price=1000 // list-auctions ``` -------------------------------- ### Stop Specific Docker Container Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/docker/readme.md Stops a specific container within the Docker Compose setup. ```bash docker compose stop ``` -------------------------------- ### Test Failover in Kubernetes Cluster Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Simulates a leader node failure in Kubernetes by killing the leader pod. The cluster will then elect a new leader, demonstrating its resilience. This is a critical test for high-availability setups. ```bash # Kill the leader to test failover: ./k8s_kill_leader.sh ``` -------------------------------- ### Get Admin Pod Name with Kubectl Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/kubernetes/readme.md Use this command to find the name of the admin container's pod in the Kubernetes cluster. ```bash kubectl get pods -n aeron-io-sample-admin ``` -------------------------------- ### Docker Compose Commands for Aeron Cluster Management Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/AWSUsageInstructions.md Provides essential commands for managing the Aeron cluster lifecycle. Use 'docker compose up -d' to start in detached mode, 'docker compose logs | grep LEADER' to find the leader node, and 'docker compose down' to stop the cluster. ```bash docker compose up -d ``` ```bash docker compose logs | grep LEADER ``` ```bash docker compose down ``` -------------------------------- ### Run Deployment Scripts for Minikube Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/kubernetes/readme.md Execute this script to build, deploy, and run the cluster and admin components on a Minikube environment. ```bash ./minikube-run.sh ``` -------------------------------- ### Sample Admin Script Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/admin/readme.md A sequence of admin commands to connect to a cluster, add an auction, add a bid, disconnect, and exit. Assumes auction ID 1 is logged. ```bash connect add-auction created-by=500 name=Tulips add-bid auction-id=1 created-by=501 price=1000 disconnect exit ``` -------------------------------- ### Connect to Admin Container with Kubectl Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/kubernetes/readme.md Execute this command to connect to the admin container and run the admin JAR. Replace `` with the actual pod name obtained from the previous command. ```bash kubectl exec -it -n aeron-io-sample-admin -- java -jar admin-uber.jar ``` -------------------------------- ### Generate Cluster Protocol Codecs Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/cluster-protocol/readme.md Run this command to generate Java sources from SBE definitions. Configuration details can be found in `build.gradle.kts`. ```bash ./gradlew generateCodecs ``` -------------------------------- ### Create Cluster Backup Tarball and Copy Out Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Creates a compressed tarball of the cluster data on the backup node and copies it to the local machine. ```bash kubectl exec -i -n aeron-io-sample-backup aeron-io-sample-backup-0 -- tar cvzf /home/aeron/jar/cluster_backup.tgz -C /home/aeron/jar/backup archive/ cluster/ kubectl cp -n aeron-io-sample-backup aeron-io-sample-backup-0:/home/aeron/jar/cluster_backup.tgz ./cluster_backup.tgz ``` -------------------------------- ### Run Deployment Scripts for Docker Desktop Kubernetes Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/kubernetes/readme.md Execute this script to build, deploy, and run the cluster and admin components on a Docker Desktop Kubernetes environment. Note that overriding the Kubernetes version is not supported with Docker Desktop. ```bash ./docker-desktop-k8s-run.sh ``` -------------------------------- ### Restore from Backup (Bash) Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Stops the cluster containers, restores the data from the previously created backup tarball to each node, and then restarts the containers. ```bash docker compose stop for i in {0..2}; do zcat cluster_backup.tgz | docker cp - aeron-node${i}-1:/home/aeron/jar/aeron-cluster; done docker compose up -d ``` -------------------------------- ### Create Cluster Backup Tarball (Bash) Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Creates a compressed tarball of the 'archive' and 'cluster' directories on the backup node and copies it to the host machine. This tarball serves as the backup. ```bash docker exec -it aeron-backup-1 tar cvzf /home/aeron/jar/cluster_backup.tgz -C /home/aeron/jar/backup archive/ cluster/ docker cp aeron-backup-1:/home/aeron/jar/cluster_backup.tgz . ``` -------------------------------- ### Environment Variables for Auto-Connect Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Configure auto-connection to the cluster and participant ID using environment variables. ```text # Auto-connect via environment: # AUTO_CONNECT=true – connect on startup using CLUSTER_ADDRESSES # PARTICIPANT_ID=500 – displayed in the console banner # DUMB_TERMINAL=true – disables ANSI escape codes (needed inside Docker exec -i) # CLUSTER_ADDRESSES=172.16.202.2,172.16.202.3,172.16.202.4 ``` -------------------------------- ### Perform Backup and Restore in Docker Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Demonstrates backing up Aeron Cluster state using `ClusterBackupAgent` and restoring it after a full cluster reset. This involves creating data, triggering snapshots, archiving, and then restoring from the archive. ```bash # --- Docker workflow --- # 1. Start cluster and create data: docker compose up -d docker exec -i aeron-admin1-1 java -jar admin-uber.jar # admin > add-auction created-by=500 name=Tulips # admin > add-bid auction-id=1 created-by=501 price=1000 # 2. Trigger a snapshot so backup has something to replicate: docker exec -it $(./docker_find_leader.sh) /home/aeron/jar/snapshot.sh # 3. Wait ~60s for backup replication; monitor backup logs: docker logs aeron-backup-1 -f # Expected: "Reached position NNNN in recording N" # 4. Archive the backup data: docker exec -it aeron-backup-1 \ tar cvzf /home/aeron/jar/cluster_backup.tgz \ -C /home/aeron/jar/backup archive/ cluster/ docker cp aeron-backup-1:/home/aeron/jar/cluster_backup.tgz . # 5. Wipe cluster state and restart fresh: docker compose down --volumes docker compose up -d # 6. Restore data to all 3 nodes from backup: docker compose stop for i in {0..2}; do zcat cluster_backup.tgz | docker cp - aeron-node${i}-1:/home/aeron/jar/aeron-cluster done docker compose up -d # 7. Verify restore: docker exec -i aeron-admin1-1 java -jar admin-uber.jar # admin > list-auctions # Auction count: 2 # Auction 'Tulips' with id 1 created by 500 is now in state PRE_OPEN ``` -------------------------------- ### Verify Clean State (Bash) Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Executes the Admin interface command to list auctions after restarting the system with a clean state. This verifies that no prior state exists. ```bash docker exec -i aeron-admin1-1 java -jar admin-uber.jar ``` -------------------------------- ### Build Docker Images Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/docker/readme.md Builds the Docker images for the Aeron cluster. Use --no-cache for a clean rebuild. ```bash docker compose build ``` ```bash docker compose build --no-cache ``` -------------------------------- ### Admin Interface: List Auctions (Empty) Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Displays the output from the admin interface when no auctions are present in the cluster. ```shell admin > connect Connected to cluster leader, node 0 admin > list-auctions No auctions exist in the cluster. Closed auctions are deleted automatically. ``` -------------------------------- ### Admin REPL Commands Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Interactive commands for the admin REPL, including connecting, adding participants and auctions, listing entities, and disconnecting. ```shell # Start the admin REPL (must be a real terminal, not Gradle run / IntelliJ): # java -jar admin/build/libs/admin-uber.jar # Or inside Docker: # docker exec -it aeron-admin1-1 java -jar admin-uber.jar # Full happy-path session: admin > connect Connected to cluster leader, node 2 admin > add-participant id=42 name=Alice Participant added: 42 admin > list-participants Participant 42 Alice Participant 500 initiator Participant 501 responder admin > add-auction created-by=500 name=Tulips Auction added with id: 1 New auction: 'Tulips' (1) Auction 1 is now in state OPEN. There have been 0 bids. admin > add-bid auction-id=1 created-by=501 price=1000 Bid accepted. Auction 1 is now in state OPEN. There have been 1 bids. Current price: 1000 admin > list-auctions Auction count: 1 Auction 'Tulips' with id 1 created by 500 is now in state OPEN admin > disconnect Cluster disconnected admin > exit # Command reference: # connect [hostnames=] [baseport=

] – connect (defaults: localhost, 9000) # disconnect – close the cluster connection ``` -------------------------------- ### Admin Interface: List Auctions (Restored) Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Displays the output from the admin interface showing the restored auctions. ```shell admin > connect Connected to cluster leader, node 0 admin > list-auctions Auction count: 2 Auction 'Tulips' with id 1 created by 500 is now in state PRE_OPEN Auction 'Daffodils' with id 2 created by 500 is now in state OPEN ``` -------------------------------- ### Connect to Admin Container Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/docker/readme.md Connects to an Aeron admin container to run administrative tools. Replace 'aeron-admin1-1' if using the second admin container. ```bash docker exec -it aeron-admin1-1 java -jar admin-uber.jar ``` -------------------------------- ### Deploy Aeron Cluster with Minikube Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Deploys the Aeron Cluster and admin components to a Kubernetes cluster using Minikube. This script builds images and applies the necessary Kubernetes manifests. ```bash # Start with Minikube: ./minikube-run.sh # builds images, applies manifests ./minikube-stop.sh # tears down ``` -------------------------------- ### Restore Cluster Data from Backup Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Stops cluster nodes, replaces their data directories with the backed-up content, and restarts the cluster. ```bash # Stop the application from writing data and remove the data directory for i in {0..2}; do kubectl exec -n aeron-io-sample-cluster aeron-io-sample-cluster-${i} -- sh -c 'kill -STOP $(pidof java); rm -r /home/aeron/jar/aeron-cluster/*'; done # Replace the data directory from the backup for i in {0..2}; do zcat cluster_backup.tgz | kubectl exec -i -n aeron-io-sample-cluster aeron-io-sample-cluster-${i} -- tar xf - -C /home/aeron/jar/aeron-cluster/; done # Restart the Cluster nodes kubectl rollout restart statefulset -n aeron-io-sample-cluster aeron-io-sample-cluster # Wait for the Cluster restart to complete kubectl rollout status statefulset -n aeron-io-sample-cluster aeron-io-sample-cluster ``` -------------------------------- ### Add Auction via Admin Interface Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Creates a new auction within the Aeron cluster using the admin command-line interface. ```shell admin > connect Connected to cluster leader, node 1 admin > add-auction created-by=500 name=Tulips duration=1800 Auction added with id: 1 New auction: 'Tulips' (1) Auction 1 is now in state OPEN. There have been 0 bids. ``` -------------------------------- ### View Backup Node Logs for Snapshot Replication Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Retrieves logs from the backup node to verify that snapshots are being replicated. ```bash kubectl logs -n aeron-io-sample-backup aeron-io-sample-backup-0 ``` -------------------------------- ### Enable Standby Feature During Build Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/standby/readme.md Use this Gradle command to enable Standby features when building the project. Ensure you have the necessary Standby binaries. ```shell ./gradlew -Pstandby=true ``` -------------------------------- ### Restart System with Clean State (Bash) Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Shuts down all Docker containers, removes associated volumes to ensure a clean state, and then restarts the containers. ```bash docker compose down --volumes docker compose up -d ``` -------------------------------- ### Create Auction Command Flow Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/cluster/src/main/java/io/aeron/samples/domain/auctions/readme.md Illustrates the sequence of messages exchanged when an auction creator initiates a new auction. The flow involves commands and results between the creator and the cluster, followed by event notifications to connected clients. ```text ┌──────────┐ ┌──────────────┐ │ ├──────────────────────────────► │ │ │Auction │ 1. CreateAuctionCommand │ │ │Creator │ │ Auctions │ │ │ │ (Cluster) │ │ │ ◄──────────────────────────────┤ │ └──────────┘ 2. CreateAuctionCommandResult │ │ (SUCCESS or validation failure)│ │ ┌──────────┐ │ │ │ │ │ │ │All │ ◄──────────────────────────────┤ │ │Connected │ 3. NewAuctionEvent if SUCCESS │ │ │Clients │ │ │ │ │ │ │ └──────────┘ └──────────────┘ ``` -------------------------------- ### Monitor Backup Node Logs (Bash) Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Streams logs from the backup node to verify that snapshot data has been successfully retrieved. This command should be run after snapshots are expected to be replicated. ```bash docker logs aeron-backup-1 -f ``` -------------------------------- ### Verify Empty Cluster State Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Connects to the admin interface after restarting to confirm that no auctions exist in the cluster. ```bash ./k8s_connect_admin.sh ``` -------------------------------- ### Take and Load Snapshots with SnapshotManager Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Use SnapshotManager to serialize and deserialize the domain state. It handles retries on back-pressure for taking snapshots and polls fragments for loading. ```java // TAKING a snapshot (called by AppClusteredService.onTakeSnapshot): // Writes: ParticipantSnapshot* → AuctionSnapshot* → AuctionIdSnapshot → EndOfSnapshot snapshotManager.takeSnapshot(snapshotPublication); // Internally uses retryingOffer() with up to 3 retries on back-pressure / admin action. // LOADING a snapshot (called by AppClusteredService.onStart when snapshotImage != null): snapshotManager.setIdleStrategy(cluster.idleStrategy()); snapshotManager.loadSnapshot(snapshotImage); // Polls the image fragment-by-fragment until end-of-stream. // Dispatches to: // ParticipantSnapshotDecoder.TEMPLATE_ID → participants.restoreParticipant(id, name) // AuctionSnapshotDecoder.TEMPLATE_ID → auctions.restoreAuction(id, creator, start, // startTimerCorrelation, end, endTimerCorrelation, // removalTimerCorrelation, winner, name, desc) // (only restored if startTime > clusterTime; already-started auctions are skipped) // AuctionIdSnapshotDecoder.TEMPLATE_ID → auctions.restoreAuctionId(lastId) // EndOfSnapshotDecoder.TEMPLATE_ID → sets snapshotFullyLoaded = true ``` -------------------------------- ### Stop and Restart Minikube Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Shuts down the current Minikube environment and then restarts it to ensure a clean state. ```bash ./minikube-stop.sh ./minikube-run.sh ``` -------------------------------- ### Run Standby with Docker Compose Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/standby/readme.md Commands to build and run Aeron Cluster with Standby features enabled using Docker Compose. This requires navigating to the docker directory and using the 'standby' profile. ```shell cd docker docker compose --profile standby build --no-cache docker compose --profile standby up ``` -------------------------------- ### Admin Interface - No Auctions (Text) Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Expected output from the Admin interface when no auctions exist in the cluster, confirming a clean state. ```text admin > list-auctions No auctions exist in the cluster. Closed auctions are deleted automatically. ``` -------------------------------- ### Connect to Admin Container in Docker Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Connects to the admin container to interact with the Aeron Cluster using its command-line interface. This is used for managing auctions and participants. ```bash # Connect to admin container: docker exec -it aeron-admin1-1 java -jar admin-uber.jar ``` -------------------------------- ### Trigger Snapshot Manually Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Manually trigger a snapshot from within a running cluster container using Docker or kubectl. ```bash # Trigger a snapshot manually from inside a running cluster container: # docker exec -it $(./docker/docker_find_leader.sh) /home/aeron/jar/snapshot.sh # kubectl exec -it -n aeron-io-sample-cluster $(./k8s_find_leader.sh) -- /home/aeron/jar/snapshot.sh ``` -------------------------------- ### Connect to Admin Shell in Kubernetes Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Connects to the Aeron Cluster's admin shell within a Kubernetes environment. This allows interaction with the cluster for management tasks. ```bash # Connect to the admin shell: ./k8s_connect_admin.sh # admin > connect # Connected to cluster leader, node 1 ``` -------------------------------- ### Connect to Aeron Cluster Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Connect to the Aeron cluster using AeronCluster.connect, configuring egress and ingress channels, and the Aeron directory name. ```java // Connecting to the cluster (triggered by REPL "connect" command or AUTO_CONNECT=true): // Internally calls AeronCluster.connect(): AeronCluster cluster = AeronCluster.connect( new AeronCluster.Context() .egressListener(adminClientEgressListener) .egressChannel("aeron:udp?endpoint=localhost:20001") .ingressChannel("aeron:udp?term-length=64k") .ingressEndpoints(ClusterConfig.ingressEndpoints(hosts, 9000, CLIENT_FACING_PORT_OFFSET)) .aeronDirectoryName(mediaDriver.aeronDirectoryName()) ); // Logs: "Connected to cluster leader, node N" ``` -------------------------------- ### Trigger Snapshot on Leader (Bash) Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Executes a script on the leader node to trigger a data snapshot. This command relies on a helper script `docker_find_leader.sh` to identify the leader container. ```bash docker exec -it $(./docker_find_leader.sh) /home/aeron/jar/snapshot.sh ``` -------------------------------- ### Docker Compose Configuration Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/AWSUsageInstructions.md The main Docker Compose file defining the services, networks, and volumes for deploying Aeron Cluster. ```yaml version: "3.7" services: aeron: image: ${IMAGE_REGISTRY}:${IMAGE_TAG} container_name: aeron_cluster ports: - "8080:8080" volumes: - ./config:/opt/aeron/config environment: - CLUSTER_NAME=my-cluster - NODE_ID=0 - SEED_NODE_ADDRESS=aeron - SEED_NODE_PORT=11111 - LOG_DIR=/opt/aeron/logs - REPLAY_DIR=/opt/aeron/replay networks: - aeron-net networks: aeron-net: driver: bridge ``` -------------------------------- ### Trigger Snapshot on Leader Node Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/backup/readme.md Executes a script on the leader node to trigger a data snapshot for replication. ```bash kubectl exec -it -n aeron-io-sample-cluster $(./k8s_find_leader.sh) -- /home/aeron/jar/snapshot.sh ``` -------------------------------- ### Docker Compose Configuration for Aeron Cluster Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/AWSUsageInstructions.md Defines the services, networks, and environment variables for a three-node Aeron cluster. Ensure the IMAGE_REGISTRY and IMAGE_TAG environment variables are set before building. ```yaml version: '3.8' name: aeron services: node0: image: ${IMAGE_REGISTRY}:${IMAGE_TAG} build: context: cluster hostname: cluster0 shm_size: '1gb' networks: internal_bus: ipv4_address: 172.16.202.2 environment: - CLUSTER_ADDRESSES=172.16.202.2,172.16.202.3,172.16.202.4 - CLUSTER_NODE=0 - CLUSTER_PORT_BASE=9000 node1: image: ${IMAGE_REGISTRY}:${IMAGE_TAG} build: context: cluster hostname: cluster1 shm_size: '1gb' networks: internal_bus: ipv4_address: 172.16.202.3 environment: - CLUSTER_ADDRESSES=172.16.202.2,172.16.202.3,172.16.202.4 - CLUSTER_NODE=1 - CLUSTER_PORT_BASE=9000 node2: image: ${IMAGE_REGISTRY}:${IMAGE_TAG} build: context: cluster hostname: cluster2 shm_size: '1gb' networks: internal_bus: ipv4_address: 172.16.202.4 environment: - CLUSTER_ADDRESSES=172.16.202.2,172.16.202.3,172.16.202.4 - CLUSTER_NODE=2 - CLUSTER_PORT_BASE=9000 networks: internal_bus: driver: bridge driver_opts: com.docker.network.bridge.enable_icc: 'true' com.docker.network.driver.mtu: 9000 com.docker.network.enable_ipv6: 'false' ipam: driver: default config: - subnet: "172.16.202.0/24" ``` -------------------------------- ### Auctions Domain Unit Test - Happy Path Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Tests the full auction creation and bid acceptance flow. Mocks dependencies like session context, participants, and responders. Verifies acknowledgments and timer scheduling. ```java // Run all tests: // ./gradlew :cluster:test // Example: full happy-path auction creation and bid acceptance @Test void testAuctionBidCanBeAdded() { when(sessionMessageContext.getClusterTime()).thenReturn(1000L); when(participants.isKnownParticipant(1000L)).thenReturn(true); when(participants.isKnownParticipant(1001L)).thenReturn(true); Auctions auctions = new Auctions(sessionMessageContext, participants, clientResponder, timerManager); String correlationId1 = UUID.randomUUID().toString(); auctions.addAuction(1000L, 1002L, 31004L, correlationId1, "name", "description"); // Verify auction was acknowledged and timers scheduled verify(clientResponder).onAuctionAdded(correlationId1, 1L, AddAuctionResult.SUCCESS, 1002L, 31004L, "name", "description"); verify(timerManager).scheduleTimer(eq(1002L), any()); // open timer verify(timerManager).scheduleTimer(eq(31004L), any()); // close timer // Fast-forward cluster time into the auction window and add a bid when(sessionMessageContext.getClusterTime()).thenReturn(31003L); String correlationId2 = UUID.randomUUID().toString(); auctions.addBid(1L, 1001L, 99L, correlationId2); verify(clientResponder).onAuctionUpdated(correlationId2, 1L, AuctionStatus.PRE_OPEN, 99L, 1, 31003L, 1001L); } ``` -------------------------------- ### Add Auction Bid Command Flow Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/cluster/src/main/java/io/aeron/samples/domain/auctions/readme.md Details the message exchange for a bidder placing a bid on an auction. This flow includes the bidder sending a command to the cluster, receiving a result, and potentially triggering an update event to all connected clients. ```text ┌──────────┐ ┌──────────────┐ │ ├──────────────────────────────► │ │ │Auction │ 1. AddAuctionBidCommand │ │ │Bidder │ │ Auctions │ │ │ │ (Cluster) │ │ │ ◄──────────────────────────────┤ │ └──────────┘ 2. AddAuctionBidCommandResult │ │ (SUCCESS or validation failure)│ │ ┌──────────┐ │ │ │ │ │ │ │All │ ◄──────────────────────────────┤ │ │Connected │ 3. AuctionUpdateEvent │ │ │Clients │ if SUCCESS │ │ │ │ │ │ └──────────┘ └──────────────┘ ``` -------------------------------- ### Schedule and Restore Cluster Timers with TimerManager Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Utilize TimerManager to schedule one-shot timers with specific deadlines and callbacks, and to restore timer mappings from snapshots. This ensures time-driven auction state transitions and cleanup. ```java // Schedule a one-shot timer at an epoch-millis deadline: long timerId = timerManager.scheduleTimer( System.currentTimeMillis() + 25_000, // deadline (epoch ms) () -> auctions.closeAuction(auctionId) // callback ); // Retries cluster.scheduleTimer() until it succeeds, using cluster.idleStrategy() // When the timer fires, AppClusteredService.onTimerEvent() is called: // timerManager.onTimerEvent(correlationId, timestamp) // → looks up the Runnable by correlationId, executes it, removes the entry // Restore timer mapping from snapshot (cluster re-fires timer automatically): timerManager.restoreTimer(savedCorrelationId, () -> auctions.openAuction(auctionId)); // Note: does NOT call cluster.scheduleTimer() – Aeron Cluster replays the timer // Each auction schedules exactly 3 timers: // 1. startTime → openAuction(id) – transitions PRE_OPEN → OPEN // 2. endTime → closeAuction(id) – transitions OPEN → CLOSED // 3. endTime + 60s → removeAuction(id) – purges auction from list ``` -------------------------------- ### Participants: Participant Domain Model Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Manages named bidding parties, with default participants pre-seeded. Ensures participants are registered before they can create or bid in auctions. ```java // Two participants are pre-seeded at startup – no registration step needed for demos: // ID 500 "initiator", ID 501 "responder" Participants participants = new Participants(clusterClientResponder); // Add a new participant (called via SbeDemuxer; sends AddParticipantCommandResult reply): participants.addParticipant(42L, "correlation-uuid-here", "Alice"); // → clusterClientResponder.acknowledgeParticipantAdded(42L, correlationId) // Check membership before allowing auction creation or bidding: boolean known = participants.isKnownParticipant(42L); // true after addParticipant // List all participants sorted by ID: List list = participants.getParticipantList(); // → [Participant(42, "Alice"), Participant(500, "initiator"), Participant(501, "responder")] // Restore from snapshot (no response sent to client): participants.restoreParticipant(42L, "Alice"); // Admin REPL equivalents: // add-participant id=42 name=Alice // list-participants ``` -------------------------------- ### Test Failover in Docker Cluster Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Simulates a leader node failure by stopping its container. The Aeron Cluster will then elect a new leader, demonstrating its fault tolerance. Monitor the cluster logs for re-election time. ```bash # Test failover – stop the leader: docker compose stop aeron-engine2-1 # Cluster re-elects; typically takes ~3s (leaderHeartbeatTimeoutNs = 3s) ``` -------------------------------- ### SBE Protocol Schema - Message Definitions Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Defines key message types for commands and responses in the cluster protocol. These are generated from an SBE XML schema. ```xml AddParticipantCommand: participantId(int64), correlationId(uuidString[36]), name(varUtf8) CreateAuctionCommand: createdByParticipantId, startTime(int64 epoch ms), AddAuctionBidCommand: auctionId, addedByParticipantId, price(int64 cents), correlationId ListAuctionsCommand: correlationId ListParticipantsCommand: correlationId AddParticipantCommandResult: correlationId, participantId CreateAuctionCommandResult: auctionId(-1 on failure), result(AddAuctionResult), correlationId NewAuctionEvent: auctionId, startTime, endTime, name, description [broadcast] AddAuctionBidCommandResult: auctionId, result(AddAuctionBidResult), correlationId AuctionUpdateEvent: auctionId, status, currentPrice, bidCount, AuctionList: correlationId + repeating group of auction entries ParticipantList: correlationId + repeating group of participant entries ``` -------------------------------- ### Docker Compose Environment Variables Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/AWSUsageInstructions.md Defines environment variables for Docker Compose, specifying the ECR image registry and tag. This file should be placed in the same directory as `docker-compose.yaml`. ```shell IMAGE_REGISTRY=709825985650.dkr.ecr.us-east-1.amazonaws.com/adaptive/aeron-premium IMAGE_TAG=cluster-sample-v0.1.0-git7e38381 ``` -------------------------------- ### Find Cluster Leader Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/docker/readme.md Finds the leader node in the Aeron cluster by searching logs or using a script. ```bash docker compose logs | grep LEADER ``` ```bash ./docker_find_leader.sh ``` -------------------------------- ### Create AWS Service Linked Role for License Manager Source: https://github.com/adaptiveconsulting/aeron-io-samples/blob/main/AWSUsageInstructions.md AWS CLI command to create the service linked role for AWS License Manager. This is required for Marketplace deployments if the role does not already exist. ```bash aws iam create-service-linked-role --aws-service-name license-manager.amazonaws.com ``` -------------------------------- ### SbeDemuxer: Ingress Message Dispatch Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Routes incoming SBE messages to the correct domain handler based on MessageHeader.templateId. Handles messages shorter than 8 bytes by dropping them. ```java // SBE template IDs (from protocol-codecs.xml): // 1 = AddParticipantCommand // 10 = CreateAuctionCommand // 13 = AddAuctionBidCommand // 30 = ListAuctionsCommand // 32 = ListParticipantsCommand SbeDemuxer demuxer = new SbeDemuxer(participants, auctions, clusterClientResponder); // Called inside AppClusteredService.onSessionMessage(): demuxer.dispatch(buffer, offset, length); // Internally routes like: // templateId == 1 → participants.addParticipant(id, correlationId, name) // templateId == 10 → auctions.addAuction(creatorId, startTime, endTime, correlationId, name, desc) // templateId == 13 → auctions.addBid(auctionId, participantId, price, correlationId) // templateId == 30 → responder.returnAuctionList(auctions.getAuctionList(), correlationId) // templateId == 32 → responder.returnParticipantList(participants.getParticipantList(), correlationId) // unknown → logs error and ignores // Messages shorter than MessageHeaderDecoder.ENCODED_LENGTH (8 bytes) are silently dropped. ``` -------------------------------- ### Auctions Domain Unit Test - Self-Bid Rejection Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Tests the rejection of a bid when the auction creator attempts to bid on their own auction. Mocks necessary dependencies. ```java // Example: self-bid rejection @Test void testAuctionRejectedIfSelfBidding() { when(sessionMessageContext.getClusterTime()).thenReturn(1000L); when(participants.isKnownParticipant(1000L)).thenReturn(true); Auctions auctions = new Auctions(sessionMessageContext, participants, clientResponder, timerManager); auctions.addAuction(1000L, 1002L, 31004L, correlationId1, "name", "description"); when(sessionMessageContext.getClusterTime()).thenReturn(31003L); auctions.addBid(1L, 1000L, 99L, correlationId2); // creator bids on own auction verify(clientResponder).rejectAddBid(correlationId2, 1L, AddAuctionBidResult.CANNOT_SELF_BID); } ``` -------------------------------- ### Restore Kubernetes Cluster from Backup Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Restores the Aeron Cluster state in Kubernetes from a backup archive. This involves stopping cluster nodes, copying backup data, and restarting the cluster. Assumes backup data (`cluster_backup.tgz`) is available. ```bash # Kubernetes backup restore (after snapshot replication to backup pod): # Stop cluster nodes, copy backup data, restart: for i in {0..2}; do kubectl exec -n aeron-io-sample-cluster aeron-io-sample-cluster-${i} \ -- sh -c 'kill -STOP $(pidof java); rm -r /home/aeron/jar/aeron-cluster/*' done for i in {0..2}; do zcat cluster_backup.tgz | kubectl exec -i \ -n aeron-io-sample-cluster aeron-io-sample-cluster-${i} \ -- tar xf - -C /home/aeron/jar/aeron-cluster/ done kubectl rollout restart statefulset -n aeron-io-sample-cluster aeron-io-sample-cluster kubectl rollout status statefulset -n aeron-io-sample-cluster aeron-io-sample-cluster ``` -------------------------------- ### Trigger Snapshot in Kubernetes Cluster Source: https://context7.com/adaptiveconsulting/aeron-io-samples/llms.txt Manually triggers a snapshot on the leader node within the Kubernetes deployment. This is used for backup purposes and to ensure data consistency. ```bash # Trigger a snapshot on the leader: kubectl exec -it -n aeron-io-sample-cluster \ $(./k8s_find_leader.sh) -- /home/aeron/jar/snapshot.sh ```