Archive for January, 2022

Enjoyed Digging Through PostGraphile Code

Monday, January 10th, 2022

TypeScript

Over the weekend, I had a problem with a project at work that was using PostGraphile and I was having an issue with the Postgres URL that I was feeding to the configuration of PostGraphile:

    postgraphile(
      process.env.PLATTER_POSTGRES_URL,
      'public',
      {
        watchPg: false,
        graphiql: true,
        enhanceGraphiql: true,
        graphqlRoute: '/graphql/v2',
        graphiqlRoute: '/graphiql/v2',
        eventStreamRoute: '/graphql/v2/stream',
        appendPlugins: [
          require('@graphile-contrib/pg-simplify-inflector'),
          require('postgraphile/plugins').TagsFilePlugin,
        ]
      }
    )

The process.env.PLATTER_POSTGRES_URL was generated by a call to the Platter service, and it turned out to be cached, and stale, and as the source is Let's Encrypt, it needs to be updated monthly. The cache had been running for more than a month, and that left an old, expired, certificate for the site, in memory.

It was easy enough to have them restart the cache, getting to that point... well... 🙂 that was a little more involved. The first issue was that with PostGraphile, used as a Library, had the feature that if it could not generate the initial schema for the GraphQL engine, it would exit the process, and effectively crash the service.

I wanted to protect the service, so the first order of business was to update the way I was using PostGraphile to allow me to capture the failure, and just disable the GraphQL engine until we could get this problem figured out. Thankfully, that was as easy as adding a function to the retryOnInitFail option:

    postgraphile(
      process.env.PLATTER_POSTGRES_URL,
      'public',
      {
        watchPg: false,
        graphiql: true,
        enhanceGraphiql: true,
        graphqlRoute: '/graphql/v2',
        graphiqlRoute: '/graphiql/v2',
        eventStreamRoute: '/graphql/v2/stream',
        appendPlugins: [
          require('@graphile-contrib/pg-simplify-inflector'),
          require('postgraphile/plugins').TagsFilePlugin,
        ],
        retryOnInitFail: (err, att) => {
          log.error(`[PostGraphQL] Error on initialization: '${err}' with ${att}
                     attempts. Bailing out on PostGraphQL.`)
          return false
        }
      }
    )

At this point, we had time to figure out what the issue was. I was going to dig into the PostGraphile code, and Alex, at Platter, was going to look at it from his end. Which brings me to the point... the PostGraphile TypeScript code is very nice. Yes, there are a lot of packages/modules, and the organization is clean, but I'd have done it the same way - easy separation of responsibilities. The code is exceptionally clean... well considered and implemented. The more I dug into it, the more impressed I was with it as a project.

I thought it might be an issue with their code - an asset they are loading that has an expired certificate, so I filed that on GitHub, and had a wonderful exchange with the maintainer of the project. As I dug in more, and worked to repeat the issue on a much more limited basis, the back and forth with the maintainer was very helpful... just exactly what you'd hope to encounter - but often don't.

It was the most unexpected, wonderful, experience I'd had in months. It renewed my faith in Open Source again. 🙂