2024-03-06 08:00:00
If there’s money for tax cuts, then there was money available for public services.
Our services are at breaking point. My county council declared that it is bankrupt for the 2023/2024 tax year. Many other councils have been doing this, more than ever before. Their first course of action was to make severe cuts to care homes and services for the elderly and disabled.
The NHS is in a dire situation, it’s a struggle to see a doctor when you need one. Waiting lists are at record highs, despite endless promises from this Tory government to reduce them.
I don’t want tax cuts, I want public services to be funded better, their employees happy, and their users happy. Make the services better for everyone. Make the infrastructure better for everyone.
I don’t want tax cuts in order to essentially pay me a dividend in return. We aren’t shareholders in a private company where the aim is the extract as much profit as possible.
I don’t need a tax cut. Tax cuts only benefit richer people, the more you earn the more the tax cut works for you. This is morally wrong. I need public services, we all need public services, transport, and functioning infrastructure.
I want my local area to be healthy, happy, clean, and well maintained.
I don’t want tax cuts.
2024-01-21 08:00:00
I've been working on adding a now page to my site, which is largely automated pulling in data from Apple Health, Strava, and last.fm.
Using the Strava api was incredibly frustrating as they force you to use OAuth. I appreciate we use OAuth to be able to authenticate multiple user's against a single application, limit access to data through scopes, and frequently rotate tokens to prevent replay attacks, but in this case I only want to access my data.
What ever happened to service's providing a simple API key? I don't want to OAuth just because I want to run a single GET query on my own data.
2023-12-30 08:00:00
2023 was by far the biggest change of my life so far. We had our first child, I lost a lot of weight, and made some big changes to my lifestyle.
I started 2023 weighing at least 120kg, I don't know how heavy I actually was. I stopped weighing myself because I didn't want to see the number.
After finding out we were expecting our first child this gave me a huge kick to get my butt into action and be more active. I knew my weight would get in the way of looking after our child, and I didn't want that to happen.
I started by walking more, after a couple of weeks I'd built up to 10km a few times a week. At the start of February I decided to go along to my first Parkrun, and have been going almost every week since. I'd also started running 5k at least twice a week, including Parkrun, sometimes this would be up to 4 times. I'd also get up at 6am to complete my 10km walk before work. Some weekends I'd cycle 40km or more, other times cycling to work which was a bit under 10km each way.
One of the biggest points here was that I avoid a gym. I knew that joining a gym, I'd give up the second I stopped going, as had happened several times over the years. I wanted to make positive changes to my lifestyle that I could stick to and involve my family.
I hit a lifetime low weight of 87kg in September, and have since been hovering around 90kg. Having our first child I moved my focus to my activity levels, worrying less about losing weight, and just maintaining it. In 2024 I want to get back to losing with a goal of 80kg.
I completed my first Parkrun on the 4th of February, as of today, 30th Dec, I just completed my 40th.
For those that don't know Parkrun is a free timed run that takes place every Saturday at 9am. It's a 5k run, jog, walk, or whatever you want it to be. It's very inclusive and there's always a wide range of abilities taking part, fast or slow, young and old, buggies and pets.
I've made consistent improvements to my time over the year, and I'm now able to consistently run 5k in under 30 minutes. My current PB is 27:26, and I hope to get this under 25 minutes in 2024.
We found out in late 2022 we were expecting our first child. This was a huge change to our lives, and we were both very excited.
We set about planning how we'd arrange the house, which room we'd use for the nursery, etc. One afternoon we were at the baby shop getting gifts for our pregnancy reveal, and while there we were looking at nursery furniture. We found the set we were happy with, and decided to measure up the room, that same day we ended up ordering all the furniture, pushchair, car seat, crib, the whole works. We might have gotten a little carried away.
I would highly recommend NCT Antenatal Courses. The classes were great for meeting a group of people in the same circumstance. We still keep in touch with them, and we've heard from others that even 10, 20, 30 years on they're still in touch with friends they made via their NCT group.
There were two main points we took away from NCT and put into practice.
Firstly, this is the most stressful thing most people will go through, so seeing the baby isn't free, they must support you in being the best parents you can. Visitors need to help around the house before baby time, be that (un)load the dishwasher, do the washing up, hang the laundry up, hoover, or cook dinner.
Secondly, write a list of hobbies and interests about yourself and your partner. Take it in turns once a week, or month to pick something from that list and spend time doing that thing while the other parent spends the day with little one. Spend deliberate time focusing on who and what you are, what you enjoy.
I'd like to say the decision behind this one was a conscious environmental decision, but that's just a happy side effect. The reality is that post-covid both of us work from home so we just don't need a second car. We'd kept our second car for 2 years after last needing it, and my wife had grown tired of having to keep driving it to maintain the battery and service of the car.
Adjusting to this took a little while, during the summer I started cycling to the office if my wife needed the car for the day. Sometimes we'd double book which left us in a bit of a pickle, others my wife would have to drop me at the office before heading off to do what she needed to.
We now have a whiteboard on the fridge where we plan our meals for the week. We also write who will need the car when.
Both sides of our family have German relations, but I'd never learned any German, bumbling my way through every visit and relying on family to translate.
This year I set about learning German using Duolingo, getting to a 100 day streak. Since our little one arrived this has been put on the back burner, so in 2024 I want to pick this up again. Particularly as we want our kid to be bilingual.
Going forward in to 2024 I want to set myself a few goals to focus on
2023-12-12 08:00:00
We recently had a problem with our Laravel queue workers. We kept finding a particular queue job kept silently failing, not always, but often enough to cause us a significant headache.
We weren't getting any of the usual logs or exceptions we'd expect with a potential timeout, memory issue, etc. We resorted to adding some debug logging in production, profiling our memory usage, etc. but nothing was helping us get to the bottom of the issue.
Eventually, I found something useful in the supervisor logs exit status 137; not expected
. Immediately I jump to it being an OOM issue, which was my suspicion, but we'd already been profiling and monitoring our usage. Nothing unexpected there, always below 100mb being used, and our limit was 128mb, the default for Laravel queue workers. Also, nothing in the syslog, or kern.log to suggest the OOM killer had been invoked.
Digging through the Laravel internals to check how the --memory
flag works, I found that gives an exit code of 12 when the limit is exceeded. So not that. Back to square one we set about refactoring the job to try and reduce the memory usage, now we're under 60mb, but still, the issue persists.
We use SQS for our queue, so we have to manually extend the job visibility timeout, otherwise SQS will release the job back to another worker. So when the job did fail we'd see the expected 15 minutes delay before another worker picked up the job again. This threw us off the scent of it being a timeout issue. Usually for a timeout issue we'd expect to see the job be retried almost immediately by another worker.
Cutting to the chase we had set private int $timeout = 60 * 15;
in the job class. This meant our manual SQS visibility timeout extension worked as expected, but Laravel couldn't read the timeout when it was serializing the object onto the queue. So when the job was picked up by a worker it would time out after the default 60 seconds and receive SIGKILL from the pcntl extension. This is what was causing the exit code 137.
The fix was to set the $timeout
property to be public, public int $timeout = 60 * 15;
so that Laravel can serialize the data onto the queue correctly.
This was compounded by the fact that PHP has some unexpected behaviour when accessing private properties of a class. If you use the null coalescing operator ??
when accessing a private property it will always evaluate to null and fallback. Usually if you access a private property you'd get an error.
None of this explains why we weren't seeing the expected timeout or max attempts exceeded exceptions, but we got to the bottom of the issue. Hopefully, this helps someone else out there.
2023-12-09 08:00:00
My family have been making this stuffing cake for quite a few years now, and it's a firm favourite of mine throughout the Christmas period. We have it with our Christmas dinner, but it's also great cold either by itself or with onion chutney.
Last year I made this for office bake day, and it went down a treat, so I thought I'd share the recipe here.
There's no exact recipe for this, is more of a chuck it all in and bake in the oven for a long as needed.
Add the onion, mushrooms, chestnuts, apple, and clementine to a food processor and blitz until roughly chopped. You can also do this by hand if you don't have a food processor.
Put the blitzed ingredients into a large mixing bowl along with the sausage meat and mix well.
Next add the stuffing mix, salt, pepper, and chilli flakes. Mix until everything is combined.
Add boiling water to the mixture until it's a thick paste. I aim for the consistency of thick porridge/oatmeal. Leave to stand for 5 minutes. The stuffing mix will absorb the water and thicken up, so add more water if needed to get the right consistency.
While the stuffing mixture is standing, line an oven dish with the streaky bacon leaving enough overhang to cover the top of the stuffing. I use a 30cm x 20cm dish, but you can use whatever you have to hand. Just make sure it's deep enough to hold the mixture.
Pour the mixture into the oven dish and spread evenly. Fold the overhanging bacon over the top of the stuffing mixture and make sure it's all covered.
Place your oven dish on a baking tray, just in case the oil and juices overflow the dish. Bake in the oven at 180°C / 350°F / Gas Mark 4 for 1 and a half hours. Then turn up to 220°C / 425°F / Gas Mark 7 for 15 minutes to crisp up the bacon. This part can vary a lot based on how deep your oven dish is, and how much water you added, so adjust the cooking time as needed.
Once cooked, remove from the oven and leave to cool before turning out onto a chopping board. Slice and serve.
2023-12-02 08:00:00
We came across a bug at work related to query strings and how there’s basically no agreed way of handling complex structures, or anything beyond strings. I guess that's a given seeing as it's a query string. The x-www-form-urlencode
spec doesn't really cover duplicate keys, but the spec does state that query strings should be parsed as a list. Even so, it appears every corner of the internet has their own, very different, implementations
Our api allows you to optionally embed entities in the request using the query string. ?embed=entity
. Fairly common on REST apis. If you want to embed multiple entities you’d use the following format ?embed[]=entity1&embed[]=entity2
. Again widespread across the internet
On several of our products that consume our api we use the qs package to build query strings from an object. This works by calling qs.stringify({ foo: ‘bar’ })
which outputs ?foo=bar
. Given an array as one of the values qs.stringify({ foo: [‘bar’, ‘baz’] })
you’d get ?foo[]=bar&foo[]=baz
so far, so good
On one of our products, we had decided to remove the qs package, instead opting to use URLSearchParams
, which is native to all modern JavaScript environments. Less packages, less bloat, less reliance on third-parties, so improvements all round
The bug in our product occurred on an endpoint on which we were requesting multiple embeds. URLSearchParams
as expected follows the x-www-form-urlencode
spec
As it turns out the array syntax our api supports in query strings seems to be a PHP flavour and not part of the aforementioned spec 🤦♂️
We quickly fixed this up with a hacky patch on the api as an immediate fix, and then set about fixing the consuming product and getting a release scheduled
My colleague @robb tooted a poll and the internet democracy soon put us right. Along with PHP, there’s some suggestion Rails also supports the same query string syntax
As the poll shows, our api, and so PHP's behaviour is just wrong, and doesn't follow the spec. There’s also some very wild implementations for behaviors from Google Drive, and BitBucket
Just because a behaviour is widespread across the internet, doesn’t mean it’s part of a spec, or that other languages will support the same thing. PHP powers over 70% of identifiable website infrastructure, but not following the spec has promoted a false sense of behavior
I've come across quite a few apis with odd query string behaviours over the years, and I just put it down to them using languages where web isn't their primary focus, but it turns out, they're just following the spec