Modeling asynchronous transactions with types — Part 1
Published: 2021-02-24 08:05:55

---
title: Modeling asynchronous transactions with types — Part 1
published: true
description: Why transactions matter - two motivating examples
tags: 
cover_image: https://images.unsplash.com/photo-1488229297570-58520851e868?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1049&q=80
---

# Scenario 1

Imagine that you're in writing a function that caches assets on S3.  The function should:

1. Write an asset to a given key/bucket.
2. Store the asset's location in a Postgres table.

Now, imagine that you accidentally write:

```javascript
await writeLocationToPgres(assetId, bucket, key);
await uploadToS3(bucket, key);
```

When things go well, there is no problem, but if something goes wrong during the write to S3, your asset cache will be out-of-sync with S3. That means that no logic will kick in to retry the upload, which means that downstream services like webpages and video renderers will not display the asset.

This sort of bug happens _all the time_ and is the reason that videos have chunks lobbed off and profile pictures disappear even though "I'm sure I uploaded it."

# Scenario 2

You work for a price comparison tool and you're contractually obliged to present quotes from 3 vendors.  You write:

```javascript
quote1 = await getQuote1();
quote2 = await getQuote2();
async sendWinningQuote([quote1, quote2]);
```

This will work for a while until Vendor #3 realizes they are getting no business from your site, at which point there are lawsuits, angry consumers, and a degradation of trust in a service. This sort of thing also happens _all the time_.

# Asynchronous transactions are hard!

In both cases, a company got bit by an asynchronous transaction. In one, the developer wrote something in the wrong order, and in the other, s/he left something out.

At Meeshkan, like in most companies, our team spends time investigating at which point of a pipeline asynchronous transactions failed.  It is _really hard_, and there is no silver bullet to ensure the correct execution, relaunching, and potential rollback of complex asynchronous transactions.

What I'd like to show in this series of articles is one strategy to reduce the number of botched asynchronous transactions.  To start, I'll revisit the two examples above, showing how both errors are prevented in my IDE (VSCode) by a type-checker (in this case, PureScript).

# Scenario 1 revisited

Check out the following program in PureScript where I write to the db _after_ I write to s3.  It compiles just fine.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7b4r3d5gsmc0h2x8tof8.png)

If, however, I invert the order, we get a red-squiggly.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2f0u9bdvlu9lmqyevnjb.png)

Plus an error message that tells us exactly what went wrong.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3eue1lv88been0hod791.png)

# Scenario 2 revisited

Check out the following program in PureScript where I get quotes from three vendors and only display information _after_ I receive all 3 quotes.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p4kx9ittox2t5rahclyv.png)

If I change the order of the quotes, it still compiles just fine, as all three are present.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/26egkce4gzza6iooyq0i.png)

However, if I leave one out, the compiler lets me know with a red squiggle.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k1zsx1m2fe8volutarz8.png)

It also lets me know exactly what I left out.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kmgp00q6xorulvih1596.png)

# What's to come

In the next article in this series (that will come out tomorrow), I will show how to build this sort of system from the ground up.  

The first article will look at how rows can create "lanes" in indexed monads to allow for indeterminate order of execution where order doesn't matter (ie from our vendor-quote example above) while enforcing certain before-after relationships where order _does_ matter.

The second article will show how these relationships can be consolidated into a type-level transition machine so that they are not defined _ad hoc_.

The third article will show how these relationships can be built into an ADT that is used to construct an indexed free monad, guaranteeing that they are the _only_ possible outcomes in a given monadic context.