Vidyano Documentation
HomepageDemo
  • Vidyano Documentation
  • Vidyano v6 (.NET 8.0 based)
    • Getting started
    • Documentation
      • Courier Feature
      • Managing User Secrets
      • Vidyano.Core
      • Icons
      • Reports
      • Grids
        • Grouping
      • Instant Search
      • Verbose Logs
        • Storage Provider
      • SourceGenerators
    • Migrating from v5.x
      • Migrating an existing Vidyano v5 project
      • Migration scripts for v5 Repository database
  • Release Notes
    • Client
      • 3.0
      • 2.0.0
    • Service
      • 6.0
      • Previous
        • 5.45.0+26864bd
        • 5.44.0+6e65421
        • 5.40.2+2a48896
        • 5.39.1+f04e696
        • 5.38.3+a697611
        • 5.37.1+3fd7ebea
        • 5.36.0+5338103
        • 5.35.5+2316022
        • 5.34.3+d278982
        • 5.33.1+12ad63a
        • 5.32.1+0c41761
        • 5.31.2+c8aabb2
        • 5.30.0+530afaf
        • 5.29.3+30608c3
        • 5.28.2+bc49431
        • 5.27.0+6b9495e
        • 5.26.2+bccf416
        • 5.25.3+8224b3b
        • 5.24.0+a20f7c
        • 5.23.0+9b8b99
        • 5.22.1+557c11
        • 5.21.1+923828
        • 5.20.0+95f4d1
        • 5.19.0+0964f9
        • 5.18.0+de3495
        • 5.17.0+aaa255
        • 5.16.0+aae2a8
        • 5.15.2+5ed89a
        • 5.14.1+ec0dbd
        • 5.13.1+c8fdb1
        • 5.12.0+66cbb5
        • 5.11.1+d7647c
        • 5.10.2+a3acd1
        • 5.9.0+68a51e
        • 5.8.1+67bcab
        • 5.8.0+aab7d8
        • 5.7.1+554316
        • 5.6.4+151e2e
        • 5.1.60401.4035
  • Legacy v5.x
    • Installation (Legacy)
    • Tutorial 1: Your first application (Legacy)
    • Computed attributes
    • Actions
      • Labels
      • Actions classes
    • Security
      • Architecture
      • Allow user registration
      • Forgot password
      • Best Practices
      • Azure AD SAML based Sign-on
      • SCIM 2.0 Service Provider
    • Overriding Vidyano Settings
Powered by GitBook
On this page
  • 1. Overview
  • 2. Enabling the Courier Feature
  • 3. How It Works
  • 4. Key Features
  • 4.1 Message Delivery Patterns
  • 4.2 Idempotent Messages
  • 4.3 Message Retry
  • 4.4 Message Expiration
  • 5. Usage Examples
  • 5.1 Defining a Message
  • 5.2 Creating a Message Handler
  • 5.3 Sending Messages
  • 5.4 Chain of Messages
  • 6. Configuration Options
  • 7. Best Practices
  • 8. Troubleshooting

Was this helpful?

Export as PDF
  1. Vidyano v6 (.NET 8.0 based)
  2. Documentation

Courier Feature

1. Overview

The Courier feature in Vidyano provides a reliable, message-based processing system built on top of RavenDB. It enables asynchronous communication between different parts of your application through a publish-subscribe pattern, supporting immediate and delayed message delivery with at-least-once guarantees.

2. Enabling the Courier Feature

To enable the Courier feature in your Vidyano application:

  1. Register the feature in your Startup.cs file:

public void ConfigureServices(IServiceCollection services)
{
    // Add other services...
    
    // Register your Courier message handlers
    services.AddRecipient<YourMessage, YourMessageHandler>();
}

3. How It Works

The Courier feature works as follows:

  1. Message Publishing: Messages are stored in RavenDB as CourierMessage documents.

  2. Message Processing:

    • A RavenDB subscription monitors the database for new messages

    • When a message is detected, the system finds the appropriate recipient(s)

    • Each recipient processes the message through its ReceiveAsync method

    • After processing, messages are marked as processed with an expiration time

  3. Message Lifecycle:

    • Created → Waiting for Processing → Processed → Expired

    • Or: Created → Delayed → Waiting for Processing → Processed → Expired

    • Or: Created → Waiting for Processing → Failed → Retry → Processed → Expired

4. Key Features

4.1 Message Delivery Patterns

  • Immediate Delivery: Messages are sent and processed as soon as possible

  • Delayed Delivery: Messages are processed after a specified time delay

  • At-Least-Once Delivery: Messages are guaranteed to be delivered at least once

4.2 Idempotent Messages

Messages can implement the IIdempotentMessage interface to ensure they are only processed once, identified by a unique identifier.

4.3 Message Retry

Failed messages can be automatically retried based on configurable retry strategies.

4.4 Message Expiration

Processed messages are automatically removed from the system after a configurable expiration period.

5. Usage Examples

5.1 Defining a Message

// Regular message
public record NotificationMessage(string Subject, string Body, string RecipientEmail);

// Idempotent message
public record OrderProcessedMessage(string OrderId, DateTimeOffset ProcessedOn) : IIdempotentMessage
{
    // Implementation of IIdempotentMessage.Identifier
    public string Identifier => $"order-processed-{OrderId}";
}

5.2 Creating a Message Handler

public class NotificationMessageHandler : IRecipient<NotificationMessage>
{
    private readonly IEmailService _emailService;
    
    public NotificationMessageHandler(IEmailService emailService)
    {
        _emailService = emailService;
    }
    
    public async Task ReceiveAsync(ReceiveArgs<NotificationMessage> args, CancellationToken cancellationToken)
    {
        var message = args.Message;
        
        // Process the message
        await _emailService.SendEmailAsync(
            message.RecipientEmail, 
            message.Subject, 
            message.Body, 
            cancellationToken);
        
        // Configure message expiration (optional, defaults to 1 day)
        args.ExpireAfter = TimeSpan.FromDays(7);
        
        // Example of sending a follow-up message
        args.Courier.Send(new NotificationLoggedMessage(message.RecipientEmail));
    }
}

5.3 Sending Messages

// Get the courier service
using var _ = ServiceLocator.GetScopedRequiredService<ICourier>(out var courier);

// Send immediate message
courier.Send(new NotificationMessage(
    "Welcome!", 
    "Thank you for registering.", 
    "user@example.com"));

// Send delayed message (relative time)
courier.DelaySend(
    new ReminderMessage("Don't forget to complete your profile."), 
    TimeSpan.FromDays(3));

// Send delayed message (absolute time)
var nextMonday = GetNextMonday();
courier.DelaySend(
    new WeeklyReportMessage(), 
    nextMonday);

// Send idempotent message
// This will only be processed once, even if sent multiple times with the same ID
courier.Send(new OrderProcessedMessage("ORD-12345", DateTimeOffset.UtcNow));

5.4 Chain of Messages

public class OrderCreatedMessageHandler : IRecipient<OrderCreatedMessage>
{
    public Task ReceiveAsync(ReceiveArgs<OrderCreatedMessage> args, CancellationToken cancellationToken)
    {
        // Process the order
        ProcessOrder(args.Message);
        
        // Start order fulfillment process by sending another message
        args.Courier.Send(new InitiateFulfillmentMessage(
            args.Message.OrderId, 
            args.Message.Items));
            
        // Schedule a follow-up message after 3 days
        args.Courier.DelaySend(
            new OrderFollowUpMessage(args.Message.OrderId, args.Message.CustomerEmail),
            TimeSpan.FromDays(3));
            
        return Task.CompletedTask;
    }
}

6. Configuration Options

The Courier system can be configured in your appsettings.json file:

{
  "Vidyano": {
    "Courier": {
      "RetryWaitTime": "00:00:30",
      "MaxDownTime": "00:05:00",
      "MaxDocsPerBatch": 25
    }
  }
}

Configuration options:

  • RetryWaitTime: Time to wait before retrying subscription connection (default: 30 seconds)

  • MaxDownTime: Maximum period the system will be down before giving up (default: 5 minutes)

  • MaxDocsPerBatch: Maximum number of messages processed in a batch (default: 25)

7. Best Practices

  1. Keep Messages Small: Store only essential information in messages.

  2. Make Messages Immutable: Use C# record types or immutable classes.

  3. Design for Idempotency: Ensure that processing a message multiple times does not cause issues.

  4. Handle Exceptions: Implement proper exception handling in your message handlers.

  5. Use Message Chains: Break complex workflows into chains of simple messages.

  6. Consider Message Expiration: Set appropriate expiration times for processed messages.

  7. Monitor the System: Implement logging and monitoring for message processing.

8. Troubleshooting

If messages are not being processed as expected:

  1. Check Subscription Status: Ensure the RavenDB subscription is active.

  2. Verify Handler Registration: Confirm that your message handlers are registered correctly.

  3. Review Message Serialization: Check that your message classes can be properly serialized/deserialized by JSON.NET.

  4. Examine Expired Messages: Look for messages that have expired before processing.

  5. Look for Exceptions: Check exception logs for errors in message handlers.

  6. Inspect RetryWaitTime: Adjust RetryWaitTime if messages are not being retried quickly enough.

  7. Disable Specific Message Types: Use the Courier{MessageTypeName}Disabled setting to temporarily disable processing of specific message types.

PreviousDocumentationNextManaging User Secrets

Was this helpful?