0 Comments Posted in:

I wrote recently about the benefits of adopting Dapr in a microservices application. In that post I focused on the "service invocation" building block. In this post, I want to highlight a particularly useful capability that is exposed by the "bindings" building block.

Dapr bindings

The concept of "bindings" in Dapr will be familiar to anyone who has worked with Azure Functions. They expose a simplified way of interacting with a wide variety of third party services.

Bindings can be "input" or "output". An input binding (also called a "trigger") allows Dapr to subscribe to events in external systems and call an endpoint on your service for you to let you know what has happened. Good examples in Azure would be subscribing to events on Event Grid or messages on Service Bus. But there are many supported bindings, including things like Twitter so you can get notified whenever something is tweeted matching your search criteria.

An output binding allows you to send data to an external service. In Azure this might be posting a message to a queue, writing a document to Cosmos DB. Or you could use it to send an SMS with Twilio.

Bindings benefits and weaknesses

One strength of bindings is that they can greatly simplify your application code as they remove a lot of the cumbersome boilerplate typically required to connect to the service.

Another advantage is that they provide a certain level of abstraction. Whilst some bindings can't be swapped out with other alternatives due to the service-specific nature of the data they deal with, the ability to swap out components has potential to be very useful in dev/test environments, where you may not want or need to actually communicate with a real service.

The key weakness of bindings is that they usually expose a fairly limited subset of capabilities of the underlying platform. So if you are a power user, then you may prefer to just use the SDK of the service directly. And of course Dapr doesn't prevent you from doing that - bindings are completely optional.

The cron binding

The binding I want to focus on particularly is a bit of a special case. It's the "cron" binding. Rather than supporting connection to an external system, this makes it easy to set up scheduled tasks.

To set this up, you need to define a component YAML file. You can just copy an example, and customise the schedule to meet your needs. This supports a regular cron syntax and some simplified shortcuts like @every 5m for every five minutes as shown below.

The only 'advanced' thing I've done is limited this component to only apply to a single Dapr service by using the scopes property - in this example the catalog service.

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: scheduled
  namespace: default
spec:
  type: bindings.cron
  version: v1
  metadata:
  - name: schedule
    value: "@every 5m"
scopes:
- catalog

Now all we need to do is listen on an endpoint that matches the name of our component. In this example it's called scheduled. Note that this will be made as a HTTP POST request, so in the example below I'm showing how a simple Node.js Express application can receive calls on the /scheduled endpoint and write a message to the console.

app.post('/scheduled', async function(req, res){
  console.log("scheduled endpoint called", req.body)
  res.status(200).send()
});

If we run this, we'll see that the /scheduled endpoint is called every five minutes by the Dapr sidecar.

And that's all there is to it. Of course, Dapr doesn't force you to use any of its building blocks, so if you already have a solution for scheduled tasks, then feel free to keep using it. But if not, it's great that Dapr provides such a simple to use option out of the box.


0 Comments Posted in:

Six years ago I blogged about how to calculate the total size of blobs in an Azure blob storage container.

Since that post, there have been two(!) new versions of the Azure Blob storage C# SDK. This post uses Azure.Storage.Blobs. And I also wanted to break down the storage by access tier.

Here's the code. You just need to provide your connection string and the name of the container:

var service = new BlobServiceClient(myConnectionString);
var containerName = "mycontainer"; 
var containerClient = service.GetBlobContainerClient(containerName);

var sizes = new Dictionary<AccessTier, long>
{
    { AccessTier.Archive, 0 },
    { AccessTier.Hot, 0 },
    { AccessTier.Cool, 0 }
};

var files = 0;

await foreach (var blob in containerClient.GetBlobsAsync()) 
{
    files++;
    sizes[blob.Properties.AccessTier.Value] += blob.Properties.ContentLength.Value;
}

Console.WriteLine($"{files} files");
foreach (var kvp in sizes)
{
    Console.WriteLine($"{kvp.Key}: {SizeSuffix(kvp.Value)}");
}

A few things of note.

First of all, we can make use of the really nice async enumerable support in C# 8 with the await foreach construct. This has been something I've wanted for a long time, and it's great to see libraries making use of this.

Second, this can be quite slow to run on a very large container. It took over three hours for one container with nearly 20 million blobs. So it's not something you necessarily want to do more times than you need to.

As always in the cloud, you should also consider cost implications. I think I'm right in saying that the only endpoint this code will call is the list blobs operation to retrieve pages of blobs which already have the size and access tier information to hand. Although storage operations are pretty cheap, it can add up when the total number of operations runs into the millions.


0 Comments Posted in:

In this post, I want to show how simple the CSS grid makes it to create a basic table layout with control over the column sizes.

In this simple example, I want my table to have two fairly small columns, with a third column being given the bulk of the remaining space.

You can see the result here:

See the Pen Grid Table by Mark Heath (@markheath) on CodePen.

The great thing about this is that thanks to CSS grid (which is available in a healthy majority of browsers now), you can achieve this whole thing with just one simple CSS rule:

.table {
    display: grid;
    grid-template-columns: 1fr 1fr 80%; 
    max-width: 480px;
}

We need to set display to grid (and I've also specified a max-width for my table). Then grid-template-columns is where the intelligent sizing comes in. I'm setting the third column to take 80 percent of the space, and then using fractional units to say that the other two columns should be the same size as each other.

As you can see from the embedded example, this means that if one of the short columns has unexpectedly long content, it doesn't cause the layout of the whole table to be reconfigured. You can also set column widths to auto and it's also worth experimenting with this to see the different results you can achieve.

And that's all there is to it. I added a couple of additional styling properties using the handy nth-child rule to give a different background colour to each column.

But finally after many years of waiting it finally seems easy to create tables in CSS without using the <table> HTML element.

Of course, I should mention that CSS is certainly not my speciality, so feel free to let me know in the comments what the correct/better way to do table layouts in CSS is!