Particular / NServiceBus

Build, version, and monitor better microservices with the most powerful service platform for .NET
https://particular.net/nservicebus/
Other
2.07k stars 648 forks source link

Messages cannot be sent from Windows to Linux using the file share data bus #7043

Closed abparticular closed 2 months ago

abparticular commented 2 months ago

Describe the bug

Description

When sending messages with databus properties from Windows to Linux, the FileShareDataBusImplementation throws a FileNotFoundException.

Expected behavior

The message is received without exceptions being thrown

Actual behavior

FileShareDataBusImplementation throws a FileNotFoundException.

Versions

All supported versions

Steps to reproduce

Note that this only affects Windows to Linux. Linux to Windows is not affected because Windows allows both forward and backward slashes to be present in a path.

Relevant log output

2024-05-30 10:49:15.648 WARN  Delayed Retry will reschedule message '6312e493-6682-48fc-b547-b180000d7a01' after a delay of 00:00:20 because of an exception:
System.IO.FileNotFoundException: Could not find file '/mnt/d/particular/samples/Version 8/file-share-databus_core_9/storage/2024-05-30_00\39240538-0c09-4fd4-876c-90fd457db3cc'.
File name: '/mnt/d/particular/samples/Version 8/file-share-databus_core_9/storage/2024-05-30_00\39240538-0c09-4fd4-876c-90fd457db3cc'
   at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirError)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, UnixFileMode openPermissions, Int64& fileLength, UnixFileMode& filePermissions, Boolean failForSymlink, Boolean& wasSymlink, Func`4 createOpenException)
   at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preallocationSize)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean useAsync)
   at NServiceBus.FileShareDataBusImplementation.Get(String key, CancellationToken cancellationToken) in /_/src/NServiceBus.Core/DataBus/FileShareDataBusImplementation.cs:line 25
   at NServiceBus.DataBusReceiveBehavior.Invoke(IIncomingLogicalMessageContext context, Func`2 next) in /_/src/NServiceBus.Core/DataBus/DataBusReceiveBehavior.cs:line 48
   at NServiceBus.DeserializeMessageConnector.Invoke(IIncomingPhysicalMessageContext context, Func`2 stage) in /_/src/NServiceBus.Core/Pipeline/Incoming/DeserializeMessageConnector.cs:line 32
   at NServiceBus.ProcessingStatisticsBehavior.Invoke(IIncomingPhysicalMessageContext context, Func`2 next) in /_/src/NServiceBus.Core/Performance/Statistics/ProcessingStatisticsBehavior.cs:line 25
   at NServiceBus.TransportReceiveToPhysicalMessageConnector.Invoke(ITransportReceiveContext context, Func`2 next) in /_/src/NServiceBus.Core/Pipeline/Incoming/TransportReceiveToPhysicalMessageConnector.cs:line 35
   at NServiceBus.RetryAcknowledgementBehavior.Invoke(ITransportReceiveContext context, Func`2 next) in /_/src/NServiceBus.Core/ServicePlatform/Retries/RetryAcknowledgementBehavior.cs:line 25
   at NServiceBus.MainPipelineExecutor.Invoke(MessageContext messageContext, CancellationToken cancellationToken) in /_/src/NServiceBus.Core/Pipeline/MainPipelineExecutor.cs:line 49
   at NServiceBus.MainPipelineExecutor.Invoke(MessageContext messageContext, CancellationToken cancellationToken) in /_/src/NServiceBus.Core/Pipeline/MainPipelineExecutor.cs:line 68
   at NServiceBus.LearningTransportMessagePump.ProcessFile(ILearningTransportTransaction transaction, String messageId, CancellationToken messageProcessingCancellationToken) in /_/src/NServiceBus.Core/Transports/Learning/LearningTransportMessagePump.cs:line 340
Exception details:
        Message ID: 6312e493-6682-48fc-b547-b180000d7a01
        Transport message ID: 73c70133-d9b2-4649-be32-f3c85f1fcda6
        Pipeline canceled: False

Additional Information

A proposed fix has been raised at:

Workarounds

An incoming message behaviour can be introduced on the Linux receiver to adjust the appropriate headers so that messages can be received

Create behavior:

class IncomingHeaderBehavior :
    Behavior<IIncomingPhysicalMessageContext>
{
    public override Task Invoke(IIncomingPhysicalMessageContext context, Func<Task> next)
    {
        var headers = context.Message.Headers;
        var databusHeaders = context.Message.Headers.Where(header => header.Key.StartsWith("NServiceBus.DataBus."));
        foreach (var header in databusHeaders)
        {
            headers[header.Key] = headers[header.Key].Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
        }

        return next();
    }
}

Register behavior:

endpointConfiguration.Pipeline.Register(typeof(IncomingHeaderBehavior), "Adjust Databus paths to use appropriate path separator");

Backported to

jpalac commented 2 months ago

@orialmog FYI this issue has been fixed.