Hi Joe!

On 2016-10-31 08:15, Joe wrote:

I have some ideas for developing a new AsyncAppenderSkeleton, based on recent experience developing a custom async appender that sends logging events to a Web API.

My current thoughts are:

1.A new base class AsyncAppenderSkeleton that can be configured to work in synchronous mode (identical to AppenderSkeleton) or asynchronous mode, where DoAppend queues events on to a FIFO queue, and has a single background thread that dequeues events and calls the existing Append methods.


This sounds mostly like the BufferingAppenderSkeleton, which only misses the background worker thread to send the buffer. Therefore the AsyncAppenderSkeleton could derive from BufferingAppenderSkeleton and override a few methods that would additionally dispatch the job to a background thread. See System.Threading.Task.Run().

2.When in asynchronous mode, there will be customizable and configurable retry logic that can call Append if it throws an exception. The retry login will be able to inspect the exception that was thrown and keep a count of the number of retries so far. For example, a derived appender that logs to a Web API might want to retry 5xx HTTP status codes, but treat 4xx status codes as permanent errors. There will no retry logic in synchronous mode as this would impact performance.


When running a task with System.Threading.Task.Run() it returns a System.Threading.Tasks.Task object that allows to inspect the outcome of the task. See:

https://msdn.microsoft.com/en-us/library/system.threading.tasks.task(v=vs.110).aspx

3.The default queue implementation would be a lossy in-memory Queue with a configurable maximum length. It might be nice to provide the possibility to plug in alternate queue implementations, such as a persistent queue using MSMQ.


We would reuse the BufferingAppenderSkeleton implementation of the queue which does (not yet) persist the queue. Please note also that MSMQ sounds like a MS only service and that would in turn mean that the .net core variant would no longer be able to benefit from the AsyncAppenderSkeleton. To me this outlines a path that we would not like to walk on.

4.A class AsyncForwardingAppender would derive from AsyncAppenderSkeleton and implement IAppenderAttachable.


That's sensible to me. Looking at the class hierarchy of other ForwardingAppender implementations composition sounds more sensible and could be preferred over inheritance. We could try and work out a generic ForwardingAppenderSkeleton implementation that can take arbitrary appenders and must no longer be derived by every appender that should become a Forwarding one.

5.It would be easy to create asynchronous versions of existing custom appenders, by changing the base class from AppenderSkeleton to AsyncAppenderSkeleton and optionally implementing some retry logic. E.g. we could have a new AdoNetAppender that can be configured to operate in synchronous mode when logging to a local database, or in asynchronous mode when logging to a cloud-based database.


The default implementation should probably be able to operate asynchronously or synchronously and change mode of operation based on a configuration flag "Asynchronous=True". This levers easy reconfiguration at runtime and has probably other benefits too.

In terms of timescales, I think it would be possible to produce something by the end of 2016.

To do it I need to reimplement AppenderSkeleton’s DoAppend methods, to enqueue events if in asynchronous mode, or call Append in synchronous mode.

I don’t want to duplicate code by reimplementing the rest of AppenderSkeleton, so I would like to do one of the following:

Option 1:

-Refactor all of AppenderSkeleton’s implementation except IAppender and IBulkAppender into a new base class AppenderSkeletonBase. This includes filtering, IOptionHandler, layout.

-Derive AppenderSkeleton and later the new AsyncAppenderSkeleton from AppenderSkeletonBase.

Option 2:

-Make AppenderSkeleton’s DoAppend methods virtual, and derive AsyncAppenderSkeleton from AppenderSkeleton.

Option 1 seems the cleanest to me; any thoughts?


Let's first write out a few thoughts and concepts. When we have a concept, the best way to get it done will hopefully be obvious.

Cheers

Reply via email to