Show HN: Onesinglecounter, a Globally Available Counter
by v3lmx | 2025-06-27 10:37:50+00:00
Hey HN,

onesinglecounter is a single globally available counter with 2 buttons: one increments by 1, the other resets to 0. The website keeps track of the largest values attained in the last minute, hour, day, week, month, year, and all time.

This is a toy/experiment website to see how anonymous people will interact: one person is enough to keep the counter close to 0, so it's interesing to me to see how high the counter can get.

The backend is written in Go, and the frontend in Svelte (no kit), using shadcn for components. They communicate using a websocket that sends updates on the current value of the counter and the recorded best values per timeframe.

I started with a naive approach of storing all the connected clients in a global state, and going through all of them on each update (eg. someone clicks one one button). However, this approach quickly fell apart when the number of clients grows: number of clients * number of events per second was too much for the server to handle (this could be also because of other mistakes on my part, the early implementations were not optimal).

I then moved on to using a tick system, where the state is updated in real time from the clients to the server, but the server only update the client every tick. This drastically improved performance, and is not even noticeable on a low tick rate.

I also moved from using a mutex protected counter to an atomic value. The golang `sync/atomic` package provides an implementation for atomic operations on numbers, which allows for lock-free updates to the counter. This simplified the code, and there is no tradeoff that I could see in this particular case.

I researched other approaches around UDP and multicast, but UDP is not available natively in browsers, which is a shame as I could have streamed the updates with way less overhead.

I also learned about `sync.Cond`, which allows for synchronization between goroutines, which allowed a simple way to notify multiple goroutines when an event occurs, such as a tick update. I ended up using an implementation with channels that I found here while researching the subject (https://blogtitle.github.io/go-advanced-concurrency-patterns...), as this was more performant in my use case that using `sync.Cond` directly (from the limited testing I did, all else being equal, the `sync` package utilized 99% CPU, vs 75% for the channel implementation. There might be something else going on here, I did not really dig into this).

Another issue that seemed simple at first but wasn't straightforward was the best values per timeframe. I ended up using a golang cron library that schedules a job to run every timeframe to potentially reset the best values to the current value of the counter. This was the simplest way I found to get the values to reset not every timeframe, but at the beginning of each timeframe.

I am very interested in hearing opinions and suggestions on how you would have tackled some of the problems I encountered!

You can check out the website at https://onesinglecounter.com, and the source code is available at github.com/v3lmx/onesinglecounter.