tonyx/Sharpino
51.0
Adequate · 22 September 2026
10.9k
lines of production code
F#
primary language
7
measurements over time
What this system is
Sharpino is an F\# event sourcing library that provides the core infrastructure for building domain-driven applications, including configurable event stores, aggregate state management, and serialization. It supports distributed caching with invalidation backplanes like Azure Service Bus and Redis, and enforces data consistency through robust optimistic locking mechanisms backed by PostgreSQL advisory locks. The system facilitates complex domain patterns such as sagas, multi-aggregate transactions, and event-driven compensation, demonstrated through a comprehensive suite of sample applications.
How it got here
2023–2024 — sample expansion and concurrency hardening
30 changes.
This period focused on expanding the library's ecosystem with diverse sample applications, including seat booking, pub management, and course systems, to demonstrate advanced event sourcing patterns. Concurrently, the team significantly hardened the PostgreSQL backend by implementing robust optimistic locking mechanisms using advisory locks to prevent race conditions in concurrent writes.
2025 — sample applications and optimistic locking
43 changes.
This period focused on expanding the library's demonstration capabilities through a series of new sample applications (Samples 7–15) covering diverse domains like shopping carts, transport logistics, and course management. Concurrently, the underlying infrastructure was hardened with robust optimistic locking mechanisms using PostgreSQL advisory locks and refined database schemas to ensure data consistency under concurrent access.
2026 — distributed caching and optimistic locking samples
17 changes.
This period focused on expanding the sample applications to demonstrate advanced event sourcing patterns, specifically multi-aggregate workflows and distributed caching strategies. The work introduced samples illustrating coordinated command execution, event-driven compensation, and GDPR-compliant data replacement, while heavily emphasizing L2 cache synchronization using PostgreSQL, Redis, and Azure Service Bus. Concurrently, the underlying database infrastructure was hardened with robust optimistic locking mechanisms using PostgreSQL advisory locks to ensure data integrity under concurrent access.
Features
Add Sharpino.Sample.Client Elmish/Fable sample application
A new sample client project has been added to demonstrate an Elmish and Fable-based frontend interacting with the Sharpino backend via Fable Remoting. This sample includes the necessary configuration files (dotnet-tools, npm, gitignore), a Vite build setup, and F\# source code (Index.fs, Main.fs) that implements a basic Todo management UI using Feliz and Bulma, serving as a proof-of-concept for this specific frontend architecture.
Sharpino.Sample.Client · high confidence
Added Account and Counter domain models with event-sourcing infrastructure
The sample application now includes complete domain definitions for Account and Counter aggregates, each featuring state management (serialization/deserialization), command interfaces (Add/Remove Amount for Account; Increment/Decrement for Counter), and event definitions (AmountAdded/Removed, Incremented/Decremented). Additionally, RabbitMQ-based background consumers have been introduced for both aggregates to handle event streaming and state synchronization.
Sharpino.Sample.10/Models · high confidence
Added Balance aggregate model and event-driven consumer for sample application
The sample application now includes a new Balance aggregate that tracks account amounts and open courses, enforcing fees for course creation (100.0M) and cancellation (50.0M) with sufficient-funds validation. This change introduces the core domain model (Balance.fs), command handling (Commands.fs), event definitions (Events.fs), and a RabbitMQ-based background consumer (Consumer.fs) that listens for events, maintains local state, and supports fallback state retrieval.
Sharpino.Sample.9/models/Balance · high confidence
Added PostgreSQL functions for optimistic locking and event insertion
The database schema now includes a new \check\_last\_event\_id\_opt\_lock\ function that enforces optimistic locking by verifying the expected last event ID and acquiring a per-aggregate advisory lock to prevent concurrent write conflicts. Additionally, several helper functions (e.g., \insert\_01\_tags\_event\_and\_return\_id\, \insert\_md\_01\_tags\_event\_and\_return\_id\) have been added to insert events into specific tables while returning the generated ID, supporting both standard and metadata-augmented event storage.
Sharpino.Sample/db · high confidence
Added PostgreSQL schema with optimistic locking and advisory locks
The database schema now includes functions for inserting events with optimistic locking checks and per-aggregate advisory locks to prevent concurrent write conflicts. It also introduces specific table structures for aggregates and their events, supporting both standard and snapshot-based event insertion patterns.
Sharpino.Sample.3/db · high confidence
Added Row2 seat-booking domain model
The sample application now includes a second row (Row2) for seat booking, mirroring the existing Row1 implementation. This adds domain files defining the Row2 aggregate context, command handler, and event definitions, enabling users to book seats in the second row (seats 6–10) using the same Sharpino event-sourcing patterns.
Sharpino.Sample.2/Domain/Row2 · high confidence
Added Stadium domain model with row reference management
The sample application now includes a new Stadium aggregate root that manages row references. Users can add or remove row references by ID, with built-in validation to prevent duplicates or removal of non-existent rows. The model supports serialization/deserialization and defines specific storage and snapshotting configurations.
Sharpino.Sample.3/Stadium · high confidence
Added Todo domain model with state management and command handling
The sample application now includes a complete Todo domain model within the \Sharpino.Sample.25/Models\ directory. This introduces a \Todo\ entity with a defined state machine (Added, Started, Completed) that enforces temporal ordering for state transitions via \Activate\ and \Complete\ commands. The implementation includes corresponding \TodoEvents\ for event sourcing and \TodoCommands\ to handle user actions like activating, completing, or updating private data, along with JSON serialization support for persistence.
Sharpino.Sample.25/Models · high confidence
Added Transport Tycoon sample domain with RabbitMQ consumers
The sample application now includes a new 'Transport Tycoon' domain within the Site and Truck aggregates. This introduces domain models for Sites (managing trucks and connections) and Transporters (trucks with location and destination data), along with their respective commands and events. Additionally, background services (consumers) have been added for both aggregates to listen to RabbitMQ queues, process incoming messages, and manage local aggregate state.
Sharpino.Sample.8/Domain · high confidence
Added generic TodosReport module for event aggregation
A new \TodosReport\ module has been introduced in the sample reports area, defining a generic \TodosEvents\<'TEvent\>\ record type. This type allows users to aggregate a list of events along with initialization and end times, providing methods to add single events or lists of events to the collection. The implementation uses a generic type parameter to support different event types, replacing a previously commented-out non-generic version.
Sharpino.Sample/reports · high confidence
Added reservation management and item tracking models with event sourcing support
The sample application now includes a new Reservation model that tracks item reservations (up to a maximum of 10 items) and supports closing specific items, alongside an Item model that manages name, description, and a reference counter. Both aggregates are implemented with event sourcing capabilities, including command handlers (Commands.fs), event definitions (Events.fs), and RabbitMQ-based background consumers (Consumer.fs) that process messages and maintain state via a fallback aggregate state retriever.
Sharpino.Sample.9/models/Reservation · high confidence
Added sample domain models for Materials, Products, and Work Orders
The sample application now includes complete domain models for managing materials, products, and work orders. The Material model supports adding and consuming inventory quantities, while the Product model serves as a placeholder for future implementation. The WorkOrder model introduces a state machine for tracking production progress, allowing orders to transition through Pending, Started, Completed, and Failed states, with validation ensuring working items are unique and initially pending.
Sharpino.Sample.16/Models · high confidence
Added script to generate optimistic locking migration scripts
A new Python script (add\_opt\_lock2.py) was added to the scratch directory. This script scans existing SQL migration files to identify specific aggregate event functions and automatically generates new migration files (20260629170000\_alter\_aggregates\_opt\_lock2.sql) that create corresponding 'opt\_lock2' versions of these functions. These new functions include optimistic locking checks for the main aggregate and any extra streams, ensuring data integrity during event insertion.
scratch · high confidence
Added seat booking domain logic for sample application
The sample application now includes a domain model for managing row seats, featuring logic to check availability, book specific seats, and retrieve available seat IDs. The booking process enforces business rules, such as preventing the isolation of a single free seat when other seats in the row are booked, and utilizes the Sharpino library's JSON serializer for state persistence.
Sharpino.Sample.2/Domain · high confidence
Added seat booking sample demonstrating multi-row transactions and optimistic concurrency
This change introduces Sharpino.Sample.2, a new example application that demonstrates event sourcing patterns for seat booking. It specifically illustrates how to handle transactions spanning multiple aggregates (rows) using the library's \runTwoCommands\ mechanism, ensuring atomicity across different event streams. Additionally, it showcases handling of optimistic concurrency and invariant preservation (such as preventing a single middle seat from being left free) through event filtering and optional pessimistic locking configurations defined in \appSettings.json\.
Sharpino.Sample.2 · high confidence
Azure Service Bus backplane support for distributed caching
Sharpino.Lib now includes an Azure Service Bus backplane implementation for FusionCache, enabling distributed cache invalidation across multiple application instances. The new \AzureServiceBusBackplane\ type integrates with \ZiggyCreatures.Caching.Fusion\ to synchronize cache states (such as \statesDetails\ and \objectDetailsAssociations\) by publishing and subscribing to Service Bus topics. This allows the library to maintain consistent cache entries across a cluster without relying on local memory or other backplane providers.
Sharpino.Lib · high confidence
Database schema and optimistic locking for Goods, Cart, and GoodsContainer aggregates
The database now supports event-sourced aggregates for Goods, Carts, and GoodsContainers with dedicated event and snapshot tables, including indexes on aggregate IDs for performance. Optimistic locking is enforced via advisory locks to prevent concurrent write conflicts, and soft deletes are supported for snapshots. The schema also includes functions for inserting events with metadata and distance tracking from the latest snapshot.
Sharpino.Sample.7/shoppingCartWithSharpinoBinary/db · high confidence
Event-sourced database schema and optimistic locking for Course and Person aggregates
The database schema for the sample application now includes dedicated event-sourcing tables (events, snapshots, and aggregate-event mappings) for both Course and Person aggregates, along with helper functions to insert events. Optimistic locking has been implemented to prevent concurrent write conflicts: the system tracks the last event ID for each aggregate and validates it during writes. To ensure correctness under concurrent access, the locking mechanism uses PostgreSQL advisory locks to serialize writes to the same aggregate, and supports checking constraints across multiple streams simultaneously.
Sharpino.Sample.14/db · high confidence
Event-sourced domain models and database schema for Materials, Products, and Work Orders
This sample application now includes the core domain models and their corresponding PostgreSQL persistence layer. The F\# code defines the Material, Product, and WorkOrder aggregates, including their state transitions (such as consuming materials or completing work orders), event definitions, and command handlers. The database schema provides the necessary tables for event streams and snapshots for each aggregate, along with stored procedures to handle event insertion. The schema also implements optimistic locking to prevent concurrent write conflicts, enhanced by advisory locks to ensure per-aggregate serialization under concurrent access.
Sharpino.Sample.17/db · high confidence
Event-sourcing database schema and optimistic locking for Ingredient, Dish, and Supplier aggregates
The database schema for the sample application now includes dedicated event streams, snapshots, and aggregate-event tracking tables for Ingredient, Dish, and Supplier entities. To support reliable event sourcing, the schema adds indexes on aggregate\_id for all event and snapshot tables, implements soft-delete flags on snapshots, and introduces a distance-from-snapshot metric on events. Optimistic locking is enforced via database functions that verify the expected last event ID before appending new events, with a final migration adding advisory locks to prevent race conditions during concurrent writes to the same aggregate.
Sharpino.Sample.6/db · high confidence
Initial repository structure and library documentation
The repository is initialized with the core Sharpino event sourcing library, including the solution file, project definitions, and source code. This release introduces the library's foundational components: an in-memory event store for testing, a PostgreSQL-based event store, and a caching layer for aggregate states. It also adds comprehensive documentation (README, CONTRIBUTING, Code of Conduct, License) and sample projects to demonstrate usage, including support for RabbitMQ message integration and soft delete functionality.
(repo-wide) · high confidence
Interactive demo for multi-node L1/L2 cache synchronization
Sharpino.Sample.22 introduces an interactive command-line application that demonstrates how L1 (in-memory) and L2 (SQL) caches synchronize across multiple application instances. The sample configures a PostgreSQL event store, an Azure SQL L2 cache, and an Azure Service Bus emulator to broadcast invalidation messages, ensuring that changes made in one instance (e.g., renaming a todo) are reflected in others. It includes the necessary Docker Compose infrastructure, SQL schema for the cache table, and configuration files to run concurrent sessions that validate this distributed caching behavior.
Sharpino.Sample.22 · high confidence
Introduce Goods aggregate with binary serialization and RabbitMQ consumer
The Goods sample now includes a complete event-sourced aggregate for managing product items, featuring a \Good\ entity with price and quantity validation, corresponding domain events (\PriceChanged\, \QuantityAdded\, \QuantityRemoved\), and command handlers that support undo operations. These components are configured to use binary serialization for state and events, and a new \GoodConsumer\ background service has been added to listen for these events from a RabbitMQ queue, enabling the Goods module to process updates via the message broker.
Sharpino.Sample.7/shoppingCartWithSharpinoBinary/Goods · high confidence
Introduce Goods domain model with event sourcing and RabbitMQ integration
The Goods sample now implements a complete event-sourced aggregate for managing product items, including price changes and quantity adjustments. The domain logic is defined in Good.fs with validation, while Commands.fs handles state transitions and implements undo capabilities for price and quantity operations. Events.fs defines the domain events (PriceChanged, QuantityAdded, QuantityRemoved) with serialization support. Consumer.fs integrates the sample with RabbitMQ, providing a background service that consumes messages and maintains local aggregate state via a concurrent dictionary, with fallback state retrieval support.
Sharpino.Sample.7/shoppingCartWithSharpino/Goods · high confidence
Introduces Student aggregate model with enrollment logic and event sourcing components
Adds the core Student domain model, including the Student entity with course enrollment/unenrollment capabilities, command definitions for Enroll and Unenroll actions, event definitions for EnrolledCourse and UnenrolledCourse, and a RabbitMQ-based consumer that manages student state using an in-memory cache.
Sharpino.Sample.11/Models/Student · high confidence
Introduces Teacher aggregate model with course management and event sourcing infrastructure
The Teacher sample now includes a complete event-sourced domain model for managing a teacher's courses. This adds a Teacher aggregate that enforces a maximum of five courses, along with corresponding CourseAdded and CourseRemoved events. The implementation includes command handlers for adding and removing courses, a RabbitMQ-based consumer for processing events, and serialization support, establishing the foundational structure for this specific sample scenario.
Sharpino.Sample.9/models/Teacher · high confidence
Introduces shopping cart domain logic with event sourcing and RabbitMQ integration
The sample application now includes a complete shopping cart implementation within the Cart module. This adds the core domain model (Cart aggregate) supporting operations to add, remove, and query goods, along with corresponding domain events (GoodAdded, GoodRemoved, GoodsAdded). It introduces command handling with undo capabilities for adding and removing items, and integrates a RabbitMQ-based consumer (CartConsumer) that listens for events, maintains local state in a concurrent dictionary, and allows fallback state retrieval. Serialization and deserialization are handled via jsonPSerializer, and the aggregate is configured with a specific storage name, version, and snapshot interval.
Sharpino.Sample.7/shoppingCartWithSharpino/Cart · high confidence
New Course aggregate model with student/teacher management and RabbitMQ consumer
The sample application now includes a complete Course domain model featuring commands to add or remove students and teachers, along with corresponding events (StudentAdded, StudentRemoved, TeacherAdded). The Course aggregate enforces constraints such as a maximum number of teachers (3) and a configurable maximum number of students. It also supports data migration from an older 'Curse001' schema. A new background service (CourseConsumer) has been added to consume events from a RabbitMQ queue, maintaining local state and supporting fallback state retrieval for consistency.
Sharpino.Sample.9/models/Course · high confidence
New Dish aggregate with ingredient management and RabbitMQ consumer
The sample application now includes a complete Dish domain model featuring an aggregate that manages ingredients via AddIngredient and RemoveIngredient commands, emitting corresponding IngredientAdded and IngredientRemoved events. A new background service consumer has been added to listen to these events from a RabbitMQ queue, maintaining local state for the aggregate and supporting fallback retrieval.
Sharpino.Sample.6/Dishes · high confidence
New Ingredients domain model with event-sourced commands and RabbitMQ consumer
The Ingredients sample now implements a full event-sourced domain for managing ingredients, including types and measures. It introduces an \Ingredient\ aggregate with methods to add or remove ingredient and measure types, paired with corresponding \IngredientEvents\. Commands are handled via an \AggregateCommand\ interface that validates state changes and produces events. A new \IngredientConsumer\ background service connects to RabbitMQ to consume these events, maintaining local state in a concurrent dictionary and supporting fallback state retrieval.
Sharpino.Sample.6/Ingredients · high confidence
New Pub Management System sample with refreshable details and JSON serialization
Added Sharpino.Sample.6, a new example demonstrating a Pub Management System built with event sourcing. This sample introduces a \PubSystem\ module that manages Dishes, Ingredients, and Suppliers, featuring a \DetailsCache\ mechanism with \RefreshableAsync\ support to efficiently aggregate dish details with their ingredients. It also includes a \Commons\ module that configures JSON serialization via FsPickler for event storage, replacing previous binary defaults in this context, and provides an \appSettings.json\ configuration file for tuning cache expirations and logging levels.
Sharpino.Sample.6 · high confidence
New SQL templates for PostgreSQL event sourcing with optimistic locking
The SqlTemplates directory now provides ready-to-use PostgreSQL migration scripts and helper utilities for setting up event-sourced aggregates and contexts. The templates define tables for events, snapshots, and aggregate-event mappings, along with PL/pgSQL functions to insert events and manage metadata. A key addition is support for optimistic concurrency control: the CheckLastEventId templates implement per-aggregate serialization using PostgreSQL advisory locks to prevent race conditions during concurrent writes. Helper shell scripts allow developers to generate concrete SQL files by substituting version, storage name, and format placeholders, and separate scripts handle granting table and sequence permissions to the 'safe' database user.
SqlTemplates · high confidence
New SeatBooking service for managing theater seating and reservations
Added a new SeatBooking service in the API layer that provides methods for managing theater rows, seats, bookings, and vouchers. This service exposes operations to add and retrieve rows, add and retrieve vouchers, add and remove seats from rows, and create and assign bookings, utilizing the underlying event store and message senders to coordinate these domain actions.
Sharpino.Sample.FormerlySaga/Api · high confidence
New Student domain model with course management and event sourcing support
Added a new Student aggregate model for the sample application, including the core entity with course add/remove logic, command definitions for adding and removing courses, event definitions for course changes, and a RabbitMQ-based consumer for processing events and maintaining state.
Sharpino.Sample.9/models/Student · high confidence
New Student2 aggregate model and event-driven consumer
This change introduces a new 'Student2' domain model within the sample application, featuring a distinct aggregate structure with course enrollment limits and annotation tracking. It includes the corresponding command handlers (Enroll, Unenroll, AddAnnotation) and event definitions (EnrolledCourse, UnenrolledCourse, AnnotationAdded) to manage state transitions. Additionally, a new background consumer service is added to process these events via RabbitMQ, utilizing an in-memory cache for state management and a fallback retriever mechanism.
Sharpino.Sample.11/Models/Student2 · high confidence
New domain models and event-sourced consumers for theater seat management
The sample application now includes a complete event-sourced domain for managing theater seating, introducing new aggregates for Theaters, Bookings, Rows, and Vouchers. Each aggregate is paired with specific commands (such as assigning seats, adding rows, or consuming vouchers) and events, along with background consumers that listen to RabbitMQ queues to maintain in-memory state and handle concurrency via fallback retrievers. This adds the underlying infrastructure for tracking seat availability and booking assignments within the sample saga.
Sharpino.Sample.FormerlySaga/Domain · high confidence
New domain models for Course, Student, and Enrollment aggregates
The sample application now includes domain models for managing courses, students, and enrollments. This change introduces the Course aggregate (supporting name renaming), the Student aggregate (supporting name renaming), and the Enrollment aggregate (supporting adding new enrollments). Each model is implemented with corresponding commands, events, and serialization logic to persist state changes.
Sharpino.Sample.15/Models · high confidence
New sample application demonstrating cross-aggregate event sourcing with soft deletes and async support
Sharpino.Sample.9 introduces a comprehensive Course Management System example that showcases advanced event sourcing patterns, including soft deletes with reference counting, multi-aggregate command execution, and conditional cross-aggregate constraints. The sample provides both synchronous and asynchronous manager implementations (CourseManager, CourseManagerAsync, ItemManager) to handle operations like enrolling students, assigning teachers with constraint checks, and managing financial balances. It supports multiple storage backends (PostgreSQL and in-memory) and optional RabbitMQ integration for event consumption, complete with a full test suite validating these complex domain interactions.
Sharpino.Sample.9 · high confidence
New sample application demonstrating event sourcing with GDPR data replacement
Sharpino.Sample.25 introduces a complete sample application that demonstrates the Sharpino event sourcing framework, including a Todo aggregate with state management and a new capability to replace sensitive data events (GDPR compliance) via \GDPRReplaceEventsByPredicate\. The sample includes a PostgreSQL-backed event store setup via Docker Compose, an in-memory storage fallback, and comprehensive tests covering todo creation, retrieval, private data updates, and the new sensible event replacement feature.
Sharpino.Sample.25 · high confidence
New sample application demonstrating event-sourced Todo, Tag, and Category management
The Sharpino.Sample project has been introduced as a new reference implementation for building event-sourced applications in F\#. It provides a complete web service (via Fable.Remoting/Giraffe) for managing Todos, Tags, and Categories, backed by an event store. The sample supports both in-memory and PostgreSQL storage backends, includes logic for state viewers and command execution, and demonstrates domain modeling with contexts and events. It also includes serialization utilities and configuration via appSettings.json, serving as a practical starting point for users adopting the Sharpino library.
Sharpino.Sample · high confidence
New sample application demonstrating multi-command execution and RabbitMQ integration
This entry introduces the Sharpino.Sample.10 project, a new sample application that showcases advanced command handling capabilities. The sample provides a CounterApi for managing counters and accounts, featuring methods to create, retrieve, and increment single or multiple aggregates. It specifically demonstrates the ability to run multiple commands across different aggregate types (counters and accounts) in a single transactional batch using pre-executed commands. The sample also includes integration with RabbitMQ for event publishing and consumption, configurable via appSettings.json, and is supported by a comprehensive test suite in Tests.fs that validates both synchronous and asynchronous multi-command scenarios.
Sharpino.Sample.10 · high confidence
New sample application for event sourcing with FSharp.SystemTextJson
Added Sharpino.Sample.11, a new example project demonstrating an event-sourced Course and Student management system. This sample replaces the previous FsPickler serialization with FSharp.SystemTextJson and includes a CourseManager and StudentManager for handling aggregate commands, bulk loading tests, and optional RabbitMQ integration for distributed state viewing via background consumers.
Sharpino.Sample.11 · high confidence
New sample demonstrating coordinated command execution for material and work order management
Added Sharpino.Sample.16, a new example project that emulates a Process Manager/Saga pattern using coordinated commands rather than event-driven command triggering. The sample introduces a MaterialManager that manages Materials, Products, and WorkOrders, ensuring atomic execution of related operations (such as consuming materials when creating a work order) via the \CommandHandler.runInitAndNAggregateCommandsMd\ API. It includes domain models for tracking quantities, a PostgreSQL-backed event store setup via Docker Compose, and a comprehensive test suite verifying material consumption, work order lifecycle transitions, and failure handling with material restoration.
Sharpino.Sample.16 · high confidence
New sample demonstrating event-driven command compensation
Sharpino.Sample.17 introduces a proof-of-concept implementation where events trigger subsequent commands, effectively acting as a process manager. Unlike previous examples that execute compensating actions synchronously, this sample uses a message sender to react to stored events (such as a work order failure) and automatically invoke new commands (like restoring material quantities). The sample includes the necessary domain models, a material manager for orchestrating these interactions, and tests verifying the end-to-end flow of material consumption and event-driven restoration.
Sharpino.Sample.17 · high confidence
New sample domain for managing tags
The sample application now includes a new domain area for managing tags, mirroring the existing categories implementation. This adds the ability to add, remove, and retrieve tags within the sample, including support for undoing tag additions via a specific undoer logic in the command handler.
Sharpino.Sample/Domain/Tags · high confidence
New seat row management sample with event sourcing
Added a new sample application (Sharpino.Sample.3/Rows) demonstrating seat row management using event sourcing. The sample includes domain models for seats and bookings, command and event definitions for operations like booking seats and adding invariants, and a RabbitMQ-based consumer for processing events. This provides a concrete example of implementing aggregate roots with invariant checking and event persistence in the Sharpino framework.
Sharpino.Sample.3/Rows · high confidence
New shopping cart sample application with event sourcing
Added a new sample application (Sharpino.Sample.7) demonstrating a multi-aggregate shopping cart system built with Sharpino. The sample includes domain models for Goods, Carts, and a GoodsContainer, along with commands, events, and a Supermarket service that coordinates operations across these aggregates. It supports both in-memory and PostgreSQL event stores, includes comprehensive tests using Expecto, and features optional RabbitMQ integration for event publishing and consumption.
Sharpino.Sample.7/shoppingCartWithSharpino · high confidence
New shopping cart sample with binary serialization and RabbitMQ support
Added a new sample application (Sharpino.Sample.7) demonstrating a shopping cart system built with Sharpino. This sample introduces binary serialization for events and state (using \binarySerializer\ in \GoodsContainer\, \Good\, and \Cart\ aggregates) and integrates RabbitMQ for event publishing/consumption (via \RabbitMqReceiver\, \GoodConsumer\, and \CartConsumer\ in tests). It includes full aggregate definitions (\GoodsContainer\, \Good\, \Cart\), command handling with undo support (\GoodsContainerCommands\), and a \SuperMarket\ facade for business logic, all configured via \appSettings.json\ and tested with Expecto.
Sharpino.Sample.7/shoppingCartWithSharpinoBinary · high confidence
New stadium seat booking sample application
Added Sharpino.Sample.3, a new example demonstrating a Stadium Seat Booking System built with event sourcing in F\#. This sample includes the core domain logic for managing stadium rows and individual seats, a \StadiumSystem\ module for coordinating commands like adding rows, booking seats, and managing invariants, and an \appSettings.json\ configuration file for event store and logging settings.
Sharpino.Sample.3 · high confidence
New transport-tycoon sample application
Adds a new sample project (Sharpino.Sample.8) that demonstrates the transport-tycoon domain exercise. It includes domain definitions (sites, connections, trucks), a command handler for managing sites and trucks, and configuration files for the event store and logging.
Sharpino.Sample.8 · high confidence
Optimistic locking and multi-aggregate event sourcing for Todo and User domains
The sample application now supports event-sourced aggregates for both Todo and User entities, including domain models, command/event handlers, and the corresponding PostgreSQL schema. New database migrations create the \events\_01\_Todo\, \snapshots\_01\_Todo\, \aggregate\_events\_01\_Todo\ tables (and identical structures for User) to store event streams and snapshots. Optimistic locking is enforced via database functions that verify the expected last event ID before inserting new events, preventing concurrent write conflicts. The locking mechanism has been hardened with advisory locks (\pg\_advisory\_xact\_lock\) to serialize writes to the same aggregate within a transaction, and extended to support checking multiple aggregate streams in a single operation, ensuring data consistency across related entities.
Sharpino.Sample.22/db · high confidence
Refactored sample application with User aggregate and Redis L2 caching
The Sharpino.Sample.28 application has been refactored to support a new User aggregate alongside the existing Todo aggregate, enabling users to be created, renamed, and have todos assigned or detached. This change introduces domain models for both entities, including their respective events, commands, and state management, along with database migrations to store these aggregates in PostgreSQL. Additionally, the sample now demonstrates a two-level caching strategy (L1 in-memory and L2 Redis) with Redis Pub/Sub as the backplane for cache invalidation, allowing multiple application instances to stay synchronized when data changes.
Sharpino.Sample.28 · high confidence
Sample 12 adds async support and binary serialization
The Sharpino.Sample.12 project demonstrates the library's new asynchronous capabilities and binary serialization. The sample now includes async variants for state viewing and command execution (e.g., GetAllStudentsAsync, AddStudent async), allowing non-blocking operations. It also switches from the previous serialization method to binary serialization via FsPickler, as indicated by the use of PgBinaryStore and binary snapshot handling in the tests and course manager.
Sharpino.Sample.12 · high confidence
Sample 14 introduces refreshable cached details and primitive ID wrappers
The Sharpino.Sample.14 example now demonstrates the 'undoers' feature and addresses primitive obsession by wrapping Guid identifiers in strongly-typed types (CourseId, StudentId). It adds a new caching mechanism for composite read models: CourseDetails and StudentDetails are now retrieved via StateView with a built-in refresher, allowing cached data to be updated on demand. The sample also includes synchronous and asynchronous CourseManager implementations, along with RabbitMQ consumers for Course and Student aggregates that use MemoryCache for local state.
Sharpino.Sample.14 · high confidence
Sample 15 introduces refreshable cached details for enrollment data
The Sharpino.Sample.15 project demonstrates a new approach to handling enrollments by using a single, independent enrollment stream instead of embedding data in student and course streams. It introduces a 'refreshable details' feature that maintains a cache of combined student and course information, automatically keeping the view in sync with updates to the enrollment, student, or course streams.
Sharpino.Sample.15 · high confidence
Sample 24 introduces multi-aggregate domain with PostgreSQL event sourcing and L2 cache invalidation
The Sharpino.Sample.24 project now demonstrates a complete event-sourced workflow involving both User and Todo aggregates, replacing the previous single-aggregate scope. It includes domain models, commands, and events for both entities, along with SQL migrations to create the necessary PostgreSQL event and snapshot tables. The sample application is configured to use PostgreSQL as the event store and integrates an L2 cache (SQL Server) with a Service Bus message system to handle cache invalidation across multiple application instances, allowing users to test optimistic locking and real-time cache synchronization.
Sharpino.Sample.24 · high confidence
Sample.27 demonstrates multi-aggregate optimistic locking and PostgreSQL L2 cache backplane
The Sharpino.Sample.27 demo now models both User and Todo aggregates with explicit domain events and commands, and introduces database-level optimistic locking via new PostgreSQL functions that validate the last event ID before appending new events. This locking logic has been extended to support cross-aggregate constraints, allowing a single command to atomically check and update multiple aggregates. Additionally, the sample configures a PostgreSQL-based L2 cache with a notification backplane (PgNotify) to synchronize cache invalidation across multiple application instances, replacing the previous Azure Service Bus dependency.
Sharpino.Sample.27 · high confidence
Shared entity models and API interface for sample application
The Sharpino.Sample.Shared library now defines the core data models (Category, Tag, Todo) and a REST API interface (ITodosApi) used by the sample application. Users interacting with this shared layer will find that entity definitions and the contract for todo, category, and tag operations are centralized here, supporting the Elmish client's communication with the backend service.
Sharpino.Sample.Shared · high confidence
Sharpino.Core library introduces configurable event evolution behavior
The new Sharpino.Core package (version 6.2.4) provides the foundational types for the F\# event sourcing library, including definitions for Events, Commands, and Undoers. A key behavioral addition is the \evolve\ function, which now supports two modes of operation: by default, it processes events strictly (throwing on errors), but it can be compiled with the \EVOLVE\_SKIPS\_ERRORS\ flag to automatically skip invalid events and revert to the last known valid state, ensuring resilience against data inconsistencies in the event store.
Sharpino.Lib.Core · high confidence
Behavioural changes
Binary serialization support for Course and Student aggregates
The sample application now implements binary serialization for the Course and Student domain models. New model files define the aggregates and their associated commands and events, utilizing a binary serializer for persistence instead of the previous JSON-based approach. This change affects how Course and Student state is stored and retrieved, ensuring compatibility with the binary format required by the updated sample.
Sharpino.Sample.12/Models · high confidence
Database schema and locking logic for Course, Student, and Student2 aggregates
The sample application's database layer now includes migration scripts and a schema dump for three aggregates: Course, Student, and Student2. Each aggregate is backed by dedicated event and snapshot tables (e.g., events\_01\_course, snapshots\_01\_course) with corresponding sequences, primary keys, foreign keys, and indexes on aggregate\_id and timestamp. The schema introduces a distance\_from\_latest\_snapshot column to the event tables and provides PL/pgSQL helper functions for inserting events and snapshots. Optimistic locking is enforced via database functions that verify the expected last event ID before writing, and the locking mechanism has been hardened with session-scoped advisory locks (pg\_advisory\_xact\_lock) to prevent race conditions under concurrent writes. The final migration also adds support for checking additional constraint streams alongside the primary aggregate.
Sharpino.Sample.11/db · high confidence
Database schema and optimistic locking for Course, Student, and Enrollment aggregates
The database now includes dedicated event-sourcing tables (events, snapshots, and aggregate-event mappings) for the Course, Student, and Enrollment aggregates, along with helper functions to insert events. A new distance\_from\_latest\_snapshot column has been added to the event tables to support snapshot-based recovery. Optimistic locking is enforced via database functions that verify the expected last event ID before writing; this mechanism was refined to use PostgreSQL advisory locks to prevent race conditions during concurrent writes, and extended to support checking multiple related streams in a single transaction.
Sharpino.Sample.15/db · high confidence
Database schema and optimistic locking for Material, Product, and WorkOrder aggregates
The sample database now includes initial migration files to create event-sourcing tables (events, snapshots, and aggregate-event mappings) for Material, Product, and WorkOrder aggregates, along with the necessary sequences, indexes, and helper functions. A subsequent migration grants full table and sequence permissions to the 'sharpino' user. The schema was extended by adding a 'distance\_from\_latest\_snapshot' column to the event tables for these aggregates. Finally, the database now supports optimistic locking for these aggregates via new stored functions that verify the expected last event ID before inserting new events, with the latest migration securing this check using PostgreSQL advisory locks to prevent race conditions during concurrent writes.
Sharpino.Sample.16/db · high confidence
Database schema for sample sagas now includes optimistic locking and advisory locks
The database schema for the Sharpino.Sample.FormerlySaga module has been updated to support robust concurrency control for event-sourced aggregates. A new stored procedure, check\_last\_event\_id\_opt\_lock, implements optimistic locking by verifying the expected last event ID before writes, and acquires a per-aggregate advisory lock (pg\_advisory\_xact\_lock) to serialize concurrent writes to the same aggregate, preventing race conditions. Additionally, specific helper functions for inserting events into booking, row, theater, and voucher aggregates have been defined to manage event persistence and ID generation within this locking framework.
Sharpino.Sample.FormerlySaga/db · high confidence
Database schema updates for optimistic locking and performance
The database schema for the Goods and Cart aggregates has been updated to support optimistic locking and improve query performance. New migrations add \is\_deleted\ columns to the snapshot tables to enable soft deletes, introduce \distance\_from\_latest\_snapshot\ columns to track event proximity to snapshots, and create indexes on \aggregate\_id\ for the events, snapshots, and aggregate-events tables. Additionally, the schema now includes PL/pgSQL functions that implement optimistic locking checks using PostgreSQL advisory locks to prevent concurrent write conflicts on the same aggregate.
Sharpino.Sample.7/shoppingCartWithSharpino/db · high confidence
Database schema updates for sample aggregates and optimistic locking
The sample application's database schema has been updated to support Theater, Row, Booking, and Voucher aggregates, each with dedicated event and snapshot tables. Soft-delete capability was added to the Row, Booking, and Voucher snapshots via a new \is\_deleted\ column. Optimistic locking was introduced for the Row, Booking, and Voucher aggregates, initially by adding a \distance\_from\_latest\_snapshot\ column and specific locking functions, then refined with a generic \check\_last\_event\_id\_opt\_lock\ function that uses PostgreSQL advisory locks to prevent concurrent write conflicts.
Sharpino.Sample.FormerlySaga/db/migrations · high confidence
Enhanced optimistic locking with advisory locks and multi-stream checks
The database schema for the Counter and Account aggregates has been updated to support more robust concurrency control. Optimistic locking now utilizes PostgreSQL advisory locks to serialize writes to the same aggregate, preventing race conditions between the check and insert steps. Additionally, the system now supports validating the last event ID across multiple streams (extra constraints) within a single operation, and a new column tracks the distance from the latest snapshot.
Sharpino.Sample.10/db · high confidence
Enhanced optimistic locking with advisory locks and multi-stream support
The database schema for the Course and Student aggregates has been updated to provide robust optimistic locking. Initial migrations introduced the core event and snapshot tables, followed by a \distance\_from\_latest\_snapshot\ column to track event proximity. Optimistic locking was first implemented via stored functions that verify the \last\_event\_id\ before writing. This was refined with a new \check\_last\_event\_id\_opt\_lock\ function that acquires a session-scoped PostgreSQL advisory lock keyed on the aggregate, preventing race conditions under concurrent writes without schema changes. Finally, the locking functions were extended to support multi-stream consistency, allowing callers to validate the state of additional streams (via \extra\_stream\_names\, \extra\_event\_ids\, and \extra\_aggregate\_ids\) in a single transaction.
Sharpino.Sample.12/db, Sharpino.Sample.3/db/migrations · high confidence
Enhanced optimistic locking with advisory locks for event-sourced aggregates
The database schema for the Todo aggregate now includes robust optimistic locking mechanisms to prevent race conditions during concurrent event writes. Initial migrations establish the core event and snapshot tables along with helper functions. Subsequent updates introduce \check\_last\_event\_id\_opt\_lock\ and specialized insertion functions (\insert\_md\_01\_Todo\_aggregate\_event\_and\_return\_id\_opt\_lock\ and \opt\_lock2\) that verify the expected last event ID before allowing new events. Crucially, the final migration upgrades the locking check to use PostgreSQL session-scoped advisory locks (\pg\_advisory\_xact\_lock\), ensuring that concurrent writes to the same aggregate are serialized at the database level, thereby eliminating the risk of lost updates or phantom inserts under standard read-committed isolation.
Sharpino.Sample.25/db · high confidence
Event sourcing database schema and optimistic locking for Site and Truck aggregates
The database schema for the Site and Truck aggregates has been established with dedicated event, snapshot, and aggregate-event tables, along with helper functions for inserting events. Optimistic locking has been implemented to prevent concurrent write conflicts: initial versions check the last event ID, which was later enhanced with advisory locks to serialize writes per aggregate safely under concurrent load. The schema also supports soft deletes for snapshots and includes indexes on aggregate IDs to optimize query performance.
Sharpino.Sample.8/db · high confidence
Introduce versioned Todo domain model with context upgrade path
The sample application now defines a versioned domain model for the Todo feature, introducing an upgraded context (\TodosContextUpgraded\) and corresponding command/event types (\TodoCommand'\, \TodoEvent'\) alongside the original versions. This change adds support for bulk operations (adding multiple todos at once) and refines category reference management in the new version, while maintaining backward compatibility through explicit version markers (\\[\<CurrentVersion\>\]\, \\[\<UpgradedVersion\>\]\) and distinct storage version identifiers (\\_01\, \\_02\).
Sharpino.Sample/Domain/Todos · high confidence
Optimistic locking support with cross-aggregate constraints
The database schema now supports optimistic locking for event insertion, allowing applications to detect and prevent concurrent modification conflicts. Initial migrations added a \distance\_from\_latest\_snapshot\ column to event tables and basic locking functions that verify the expected last event ID before inserting new events. Subsequent migrations refined this by introducing a generic \check\_last\_event\_id\_opt\_lock\ function and updated insertion functions (e.g., \insert\md\...\_opt\_lock2\) that accept arrays of extra stream names, event IDs, and aggregate IDs. This enables cross-aggregate consistency checks, ensuring that related aggregates across different streams remain consistent during a single transaction.
Sharpino.Sample.9/db · high confidence
Refactored sample to support async refreshable details and PostgreSQL-based L2 caching
The Sharpino.Sample.26 application has been refactored to demonstrate a multi-node caching architecture with PostgreSQL as the event store and an L2 cache (backed by SQL Server or PostgreSQL) synchronized via Azure Service Bus. This update introduces new domain models for Users and Todos, along with specific database migrations for event streams and snapshots. A key behavioral change is the introduction of 'refreshable details' (e.g., \UserDetails\, \TodoDetails\) that allow UI components to fetch initial data and later refresh it asynchronously, ensuring consistency across multiple running instances of the sample app.
Sharpino.Sample.26 · high confidence
Sample app configuration and shared types updated
The sample application now uses a standard appSettings.json file for configuration, replacing the previous sharpinoSettings approach, and includes a new Commons module defining shared type aliases (RowId, BookingId, VoucherId) as Guids.
Sharpino.Sample.FormerlySaga · medium confidence
Sample database schema and optimistic locking mechanism updated
The sample application's database migrations now include new tables and functions for tags, todos, and categories, establishing the underlying storage structure for these entities. Additionally, the optimistic locking function \check\_last\_event\_id\_opt\_lock\ has been updated to use PostgreSQL advisory locks (\pg\_advisory\_xact\_lock\), ensuring that concurrent writes to the same aggregate are serialized and preventing race conditions that could occur with the previous plain SELECT approach.
Sharpino.Sample/db/migrations · high confidence
Shopping cart sample now uses binary serialization
The shopping cart sample in the \shoppingCartWithSharpinoBinary\ directory has been updated to use binary serialization instead of the previous format. This change involves new implementations for the Cart aggregate, commands, events, and a RabbitMQ consumer, all utilizing \FsPickler\ for binary serialization and deserialization of state and messages.
Sharpino.Sample.7/shoppingCartWithSharpinoBinary/Cart · high confidence
Supplier domain model and event-driven processing updated
The Suppliers sample now implements the Supplier aggregate as a class with explicit ChangePhone and ChangeEmail commands that produce PhoneChanged and EmailChanged events. A new background consumer connects to RabbitMQ, maintains an in-memory state cache, and processes incoming events to keep the aggregate state current.
Sharpino.Sample.6/Suppliers · high confidence
Test coverage
Added database migration scripts for sample event-sourcing tests; Added database schema and helper functions for event store tests; Added integration tests for the Saga sample application; Added integration tests for the Transport Tycoon network simulation; Added seat booking sample tests; Added test models for ContextObject and SampleObject aggregates; Added test suite for Stadium Seat Booking sample; Added test suite for multi-tier aggregate caching and event store operations; Added test suite for the PubSystem sample; Added tests for L2 cache and PostgreSQL notification invalidation; Added tests for L2 cache verification with Postgres and Redis; Initial test suite for Sharpino sample application.
Dependencies
Sharpino library and samples target .NET 10 alongside .NET 9 and 8
The Sharpino event sourcing library and its accompanying sample applications now support .NET 10.0 as a primary target framework, in addition to existing support for .NET 9.0 and .NET 8.0. This update aligns the core library (Sharpino.Core and Sharpino.Lib) and the various sample projects with the latest .NET runtime, ensuring compatibility with modern .NET features and performance improvements while maintaining backward compatibility with previous LTS and current releases.
(dependencies) · high confidence
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
How this codebase got here
Score
- CAI 53 → 51 (-1.6)
- Rubric changed (rubric-2026.08.19 → rubric-2026.09.15) — scores are not directly comparable.
Lenses
- Code Health 57 → 56 (-0.8)
- Architecture 86 → 81 (-5.1)
- Maturity 75 → 71 (-4.0)
- Readiness 35 → 35 (+0.5)
- Security 86 → 76 (-10.3)
Resolved (360)
- Change coupling: Commands.fs ↔ Commands.fs (Sharpino.Sample/Domain/Categories/Commands.fs)
- Change coupling: Context.fs ↔ Events.fs (Sharpino.Sample/Domain/Categories/Context.fs)
- Change coupling: Context.fs ↔ Events.fs (Sharpino.Sample/Domain/Tags/Context.fs)
- Change coupling: Events.fs ↔ Events.fs (Sharpino.Sample/Domain/Categories/Events.fs)
- Change coupling: Events.fs ↔ Events.fs (Sharpino.Sample/Domain/Categories/Events.fs)
- Change coupling: Events.fs ↔ Events.fs (Sharpino.Sample/Domain/Tags/Events.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/AzureServiceBusBackplane.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/CommandHandler.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/CommandHandler.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/CommandHandler.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/CommandHandler.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/CommandHandler.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/MemoryStorage.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/MemoryStorage.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/PgBinaryEventStore.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/PgBinaryEventStore.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/PgBinaryEventStore.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/PgEventStore.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/RabbitMq.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/StateView.fs)
- …and 340 more
New (500)
- AggregateCache3.Memoize (cognitive 21) (Sharpino.Lib/Cache.fs)
- AggregateCache3.MemoizeAsync (cognitive 21) (Sharpino.Lib/Cache.fs)
- Change coupling: AppVersions.fs ↔ Commands.fs (Sharpino.Sample/AppVersions.fs)
- Change coupling: CommandHandler.fs ↔ MemoryStorage.fs (Sharpino.Lib/CommandHandler.fs)
- Change coupling: CommandHandler.fs ↔ PgEventStore.fs (Sharpino.Lib/CommandHandler.fs)
- Change coupling: Commands.fs ↔ Commands.fs (Sharpino.Sample/Domain/Tags/Commands.fs)
- Change-coupling hub: Commands.fs → AppVersions.fs, Commands.fs, Context.fs, Events.fs, Commands.fs (Sharpino.Sample/Domain/Categories/Commands.fs)
- Change-coupling hub: Events.fs → AppVersions.fs, Commands.fs, Context.fs, Events.fs (Sharpino.Sample/Domain/Categories/Events.fs)
- Change-coupling hub: Events.fs → AppVersions.fs, Commands.fs, Context.fs, Events.fs, Commands.fs, Context.fs, Events.fs (Sharpino.Sample/Domain/Todos/Events.fs)
- Change-coupling hub: Events.fs → AppVersions.fs, Context.fs, Commands.fs (Sharpino.Sample/Domain/Tags/Events.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/CommandHandler.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/CommandHandler.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/CommandHandler.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/MemoryStorage.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/PgBinaryEventStore.fs)
- Duplicated block (10 lines × 2) (Sharpino.Lib/StateView.fs)
- Duplicated block (10 lines × 2) (Sharpino.Sample/App.fs)
- Duplicated block (10 lines × 3) (Sharpino.Lib/CommandHandler.fs)
- Duplicated block (10 lines × 3) (Sharpino.Lib/CommandHandler.fs)
- Duplicated block (10 lines × 3) (Sharpino.Lib/MemoryStorage.fs)
- …and 480 more
Changes since last survey
- 14 commits — 14 feature/other, 0 fixes
By area
- (root) — 8 commits
- (repo) — 2 commits
- Sharpino.Lib.Test/AggregateCache3Tests.fs — 1 commit
- Sharpino.Lib.Test/EventStoreTests.fs — 1 commit
- Sharpino.Lib/Cache.fs — 1 commit
- Sharpino.Lib/CommandHandler.fs — 1 commit
Notable commits
- change: L2_cache enhance
- change: Make use of the AsyncKeyedLock locker.
- change: Merge branch 'main' into 20260913_mailbox_proc_single_stream
- change: Merge pull request #72 from MarkCiliaVincenti/AsyncKeyed
- change: add note of new "lock-check" db function
- change: info vers. 6.2.6
- change: lib update + "unforgiving errors" of getAllAggregateStatesAsync
- change: link to new video
- change: mailboxprocessor + r/w separate connections
- change: readme
- change: readme
- change: v. 6.2.4
- change: vers. 2.6.5
- change: wip
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
Survey your own repository
tonyx/Sharpino was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.
About this page
- The score is its most recent published measurement, taken on 22 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
- Measured at commit f5b578823896a084f4e285c9ea435e9179b2ef59 — the exact code this score is about.
- Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
- Measured by watchdog.canine.dev using codehealth-analyzer preprod-90d5d2fe38ee.