Service healthcheck pattern

This is a simple pattern I’ve used on a number of projects to implement healthchecks as part of service monitoring. Whether you are making a scaled complex microservice solution or a simple web to API to database solution, having a set of consistent healthcheck URLs for all your components is extremely useful.

It requires two URLs on each web component in your architecture:

  • Healthcheck (e.g. /healthcheck) – returns 200 if the component thinks it is working correctly and can use it’s dependencies. This means checking it can hit any datastore required, reach any APIs it uses.
  • Status (e.g. /status) – returns 200 with no side effects

If either endpoint returns something other than 200 you know something is wrong, the healthcheck URL may respond with details on what’s failed but the status URL simply responds if the service is reachable and alive.

Most documentation on healthchecks only concern themselves with a healthcheck URL, which is fine when you are dealing with an individual component, but when you have a number of interconnected components which may also be interrogated by other applications (service discovery, load balancer etc.) having a status endpoint which does not trigger side effects is important.

Healthchecks can be expensive, making IO/network calls which place load on not just the component but other resources and services. A common issue is healthchecks causing cascades of requests to dependencies and other healthchecks after a release, which may cause false positives for failure when services take longer than usual to respond. Having the status URL means you can reduce the number of calls to the expensive healthcheck, offloading calls that only need to know if the component is alive.

Advertisements

Paging and sorting pattern for non-Javascript and Datatables

I like JQuery Datatables. It’s a easy to use JQuery plug-in that allows you to enhance an HTML table to support paging/sorting/filtering and all sorts of functionality with little configuration. It supports server side processing (something I’ve blogged on before) to allow serving large datasets.

But it has some issues.

By default it isn’t responsive and doesn’t play nice with small screens, it’s hard to style if you are using custom styling for your website and it will cause some accessibility issues. Also it needs Javascript, so sites that need to support no-js can’t rely on it for paging large tables.

Since I like the Datatables command patterns for API calls and don’t like duplicating logic, I’ve created this sample projectwhich shows how you can implement your model/view/controller logic and back-end logic to support serving a paged/sorted table both with Datatables and pure HTML GET requests on a page. This cuts down on the amount of logic needed and provides an easy to follow pattern for retrieving and using the paged data.

Even if you do not want to use Datatables it’s always good to use an approach which will be familiar to other developers and have a pattern that encourages code reuse and consistency.

Here’s the sample Person list using Datatables:

person-list-js

Here’s the same page with Javascript disabled using HTML GET requests for paging/sorting:

person-list

Datatables provides the quick AJAX redraw of the table with enhanced paging/sorting functions, while the HTML GET provides the non-Javascript support.

To implement this I used a number of classes with generics/abstract methods to allow re-use for different pages/tables:

PagedSortedViewModel – model that can be used for both JSON serialization in Datatable server-side and rendering HTML table.

   public class PagedSortedViewModel<TData> : IPagedSortedViewModel
   {
       public int Draw { get; set; }
       ...
       public IEnumerable<TData> Data { get; set; }
       ...
   }

PersonPagedSortedTableController – controller with routes for both HTML GET and Datatables JSON call

    public class PersonPagedSortedTableController : Controller
    {
        ...
        [HttpGet]
        public async Task<IActionResult> Index(int start = 0, int length = 10, string orderColumn = "Name", bool orderAscending = true)
        {
            var model = await GetPagedSortedResultsAsViewModel(0, start, length, orderColumn, orderAscending);

            return View(model);
        }

        [HttpGet]
        public async Task<JsonResult> DatatableJson(int draw = 0, int start = 0, int length = 10)
        {
            var isAscending = Request.Query["order[0][dir]"] == "asc";
            int columnIdentifier = Convert.ToInt32(Request.Query["order[0][column]"]);
            string orderColumnName = GetColumnName(columnIdentifier);

            var model = await GetPagedSortedResultsAsViewModel(draw, start, length, orderColumnName, isAscending);

            return Json(model);
        }

        private async Task<PagedSortedViewModel<PersonResultItem>> GetPagedSortedResultsAsViewModel(int draw, int start, int length, string orderColumn, bool orderAscending)
        {
            var result = await _pagedSortedRepository.GetPagedSortedResults(start, length, orderColumn, orderAscending);

            return new PagedSortedViewModel<PersonResultItem>
            {
                Draw = draw,
                ...
                Data = result.data,
            };
        }

        private string GetColumnName(int columnIdentifier)
        {
            switch (columnIdentifier)
            {
                case 0: return "Name";
                ...
            }

        }
    }

AbstractPagedSortedRepository – abstract repository class that has a number of virtual and abstract methods, wiring together the queries needed to return the paged/sorted result set so that minimal custom logic is needed for each different table.

    public abstract class AbstractPagedSortedRepository<TResultItem> : IPagedSortedRepository<TResultItem>
    {
        public async Task<PagedSortedResult<TResultItem>> GetPagedSortedResults(int start, int length, string orderColumn, bool orderAscending)
        {
            var innerJoinQuery = GetQuery();

            var recordsTotal = await GetRecordsTotalQuery(innerJoinQuery).CountAsync();

            var whereQuery = GetWhereQuery(innerJoinQuery);

            var recordsFiltered = await GetRecordsFilteredQuery(whereQuery).CountAsync();

            var sortedWhereQuery = GetSortedWhereQuery(whereQuery, orderColumn, orderAscending);

            var pagedSortedWhereQuery = sortedWhereQuery.Skip(start).Take(length);

            var data = await pagedSortedWhereQuery.ToListAsync();

            return new PagedSortedResult<TResultItem>
            {
                recordsTotal = recordsTotal,
                recordsFiltered = recordsFiltered,
                data = data,
            };
        }
        ...
    }

PersonPagedSortedRepository – Implementation of the abstract repository for a table showing joined results of the Person/Party entities.

public class PersonPagedSortedRepository : AbstractPagedSortedRepository<PersonResultItem>
    {
        ...
        protected override IQueryable<PersonResultItem> GetQuery()
        {
            return from p in _partyDbContext.Parties
                   join o in _partyDbContext.Persons on p.PartyId equals o.PartyId
                   select new PersonResultItem { PartyId = p.PartyId, Name = p.Name, EmailAddress = o.EmailAddress, DateOfBirth = o.DateOfBirth, DateCreated = p.DateCreated };
        }

        protected override IQueryable<PersonResultItem> GetSortedWhereQuery(IQueryable<PersonResultItem> whereQuery, string orderColumn, bool orderAscending)
        {
            switch (orderColumn)
            {
                case "Name": return orderAscending ? whereQuery.OrderBy(x => x.Name) : whereQuery.OrderByDescending(x => x.Name);
                ...
                default: return whereQuery;
            }
        }
    }

The view renders the table, and has Javascript to use Datatables if Javascript is enabled (hiding HTML paging/sorting controls).

Links:

The symmetrical architecture trap

Often when thinking about topics to write about I hesitate, as in retrospect what I’m saying seems obvious. But it’s very common to fall into simple patterns when you are in the thick of a project, doing something which the flaws only become apparent later when early chaos is over and you can think clearly.

One of these traps is symmetrical application architecture, making two similar components in your solution use the same architecture, even when they have different requirements.

A common example of this is when a web application will have a public facing external site and a more secure internal site for administration. On the surface these two components have similarities, they both serve HTML and need to access/persist data, so you may initially use the same architecture for them.

Symmetric architecture diagram

However, you soon realise the external site needs to handle much more traffic than the internal, and it’s data requirements are different (higher read or write, only needing access to specific data). You can resolve this by scaling the architecture, but it’s clunky.

Symmetric architecture with external load diagram

Then you realise the internal site has more security and auditing requirements. You can resolve with implementation changes but it would be neater to include additional layers or services.

Symmetric architecture with internal audit security diagram

The symmetry of the architecture becomes a conceptual barrier to change, changing either one appears to be introducing more complexity but in reality the implementations are diverging anyway due to their different circumstances. Looking at them individually and at how they will be hosted on less abstract infrastructure diagrams can help. Could be your external and internal sites don’t need the same data store or layers, and changing them could save resources and simplify implementation.

Asymmetric architecture diagram

Embracing asymmetry in your architecture early can help you break out of this mindset and prevent you hitting problems later when your implementation work arounds start to creak.

Microservice authentication and authorisation

Below is a sequence diagram describing a common pattern for handling authentication and authorisation in a microservice solution, where you have a number of small web services interconnected and don’t want them all having to implement  authentication and authorisation individually, just to be simple services focused on their job.

Microservice authentication and authorisation seq

Using this pattern you can have any number of business microservices, all using the authentication automatically and calling the same authorisation service when necessary, making them simpler to implement and re-using the services easier.

You can go a step further and put the authorisation checks in the reverse proxy against each service endpoint but this requires the reverse proxy to know the actions/permissions of each service, plus it’s likely your services permissions will be dynamic based on execution.

Nginx with lua scripts are a good way of implementing the smart reverse proxy, below are some links about this.