Skip to content

Instantly share code, notes, and snippets.

View tomliversidge's full-sized avatar

Tom Liversidge tomliversidge

  • Tallinn, Estonia
View GitHub Profile
{
"$schema": "https://json.schemastore.org/resume",
"basics": {
"name": "Tom Liversidge",
"label": "Software Developer",
"image": "",
"email": "tom@liversidge.me",
"phone": "",
"url": "https://github.com/tomliversidge",
"summary": "Software developer who believes in making the best use of technology to deliver value to customers. Main experience in C# and .net back-end development, but can also dip into front-end development and deploy infrastructure when needed. Open to using the most suitable technology to deliver great solutions. Experience includes:\n\n* Software development, architecture, design, methodologies and best practices\n* Back-end development using C#, .net and to a lesser extent, node.js\n* Front end development using React, Typescript, HTML, CSS, and JavaScript\n* Driving a cloud-native, infrastructure-as-code mentality, with experience in Terraform and AWS\n* Mix of SQL and NoSql database experience, including EventStore, PostgreSQL, MongoDb, Couchbase, SQLSer
A few years ago, I was building a SaaS application for podcasting. Early on in the life of the system, I ran in to a major failure. The front-end crashed. Hard. The site was down and my error reporting system was filling up my inbox with issues related to connectivity and message queue system. My house seemed to be crumbling all around me, and I was in full panic mode.
To have it go down during business hours (U.S. time) would be less than ideal - or, really, a disaster. But in spite of what turned out to be 2 weeks of intermittent crashes and problems, I didn’t lose any important data or have any service outage in serving podcast episodes. Yeah, the front end website was down a lot. But the primary service - sending RSS and podcast episodes to subscribers - ran without a hitch... all thanks to a robust architecture centered around RabbitMQ!
A Series Of Unfortunate Events
It started with a network problem between my server and RabbitMQ instance service. I spent almost an entire working day babysitting the
private void CheckForCompletion(PID pid)
{
_transfers.Remove(pid);
var remaining = _transfers.Count;
//... write status to console.
if (remaining == 0)
{
//... output results
public Task ReceiveAsync(IContext context)
{
switch (context.Message)
{
case SuccessResult msg:
_successResults++;
CheckForCompletion(msg.Pid);
break;
case UnknownResult msg:
_unknownResults++;
public Task ReceiveAsync(IContext context)
{
switch (context.Message)
{
//...
case Started _:
var random = new Random();
_inMemoryProvider = new InMemoryProvider();
for (int i = 1; i <= _numberOfIterations; i++)
internal class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Starting");
var random = new Random();
var numberOfTransfers = 1000;
var uptime = 99.99;
var retryAttempts = 3;
var refusalProbability = 0.01;
private readonly Dictionary<PID, object> _processedMessages = new Dictionary<PID, object>();
public Task ReceiveAsync(IContext context)
{
switch (context.Message)
{
case Credit msg when _processedMessages.ContainsKey(msg.ReplyTo):
replyTo.Tell(_processedMessages[replyTo]);
return Actor.Done;
case Credit msg:
var retryAttempts = 10;
var supervisionStrategy = new OneForOneStrategy((pid, reason) =>
SupervisorDirective.Restart, retryAttempts)
Actor.FromProducer(() => new TransferProcess(...)
.WithChildSupervisorStrategy(supervisionStrategy);
public async Task ReceiveAsync(IContext context)
{
switch (context.Message)
{
//...
case Stopping msg:
_stopping = true;
break;
case Restarting msg:
_restarting = true;
private async Task AwaitingCreditConfirmation(IContext context)
{
switch (context.Message)
{
case Started _:
context.SpawnNamed(TryCredit(_to, +_amount), "CreditAttempt");
break;
//..... other code omitted
}
}