Introducing CW: a cache watcher for Symfony

Published on 2020-05-15 • Modified on 2020-12-05

In this post, I will introduce you to Cw which is an acronym for "Cache Watcher". Cw is a small Go (Golang) program that watches your Symfony files and warms your cache when needed, so you don't have to wait when refreshing your browser. Let's go! 😎

» Published in "A week of Symfony 698" (11-17 May 2020).

Prerequisite

I will assume you have a basic knowledge of Symfony and the commands related to the cache.

Introduction

For this project, when I create a new blog post, as I write in both English and French, I always have a lot of modifications to do in my translations files. Each time, the cache has to be refreshed. Recently, I played a lot with Webpack Encore, and it provides a watch command yarn run encore dev --watch. As soon as you modify a Js or CSS file, the dev compiled assets are refreshed. That's why I had the idea to do the same thing but for the standard application cache.

Let's get lazy. I've already written markdown documentation on the GitHub repository; it took quite a lot of time. Maybe more than writing the Go program itself! So, why do the job twice? We can get the raw content of the markdown file on Github with the Symfony HTTP client.

Then convert it to HTML thanks to the markdown_to_html Twig filter. (which is made available by the erusev/parsedown and twig/markdown-extra composer dependencies). Each time the repository is modified, the change will be automatically reflected on this blog post.

Now, here is the documentation as it appears on Github, see you at the "conclusion" paragraph (if you are still there!).


CacheWatcher

CacheWatcher is a small Go program that watches your Symfony files and updates your cache when needed, so you don't have to wait when refreshing your browser.

Its goal is to improve the Developer Experience with Symfony (DX).

The Cw mascot

How does it work? πŸ€”

The program "watches" your files (.env, YAML, Twig, Doctrine entities) and as soon as it detects a modification, it calls the Symfony cache:warmup command to refresh the cache. It's important to understand that the program will not create nor delete files on your filesystem by itself.

Installation πŸ› οΈ

You can build the program yourself (this means that you must have a working Go development environment) or you can download an executable. The program was developed with go1.17.2.

Compiling the program βš™οΈ

$ git clone git@github.com:strangebuzz/cache-watcher.git
$ cd cache-watcher
$ make build 

It will build the cw or cw.exe executable depending on your platform.

Downloading the executable πŸ”½

Here are the executables for the main operating systems:

Operating System Platform version date file SHA checksum
darwin (macOS Intel) amd64 0.5.0 2022-05-12 cw (3.3mo) 80b4011567c71aef7a13e9bbdad9acacee124acb330222fa2b2abf172ce2879e
darwin (macOS M1) arm64 0.5.1 2022-05-12 cw (2.8mo) 0ba1a666c15900601c0b55762ce839a60309cb81a302fdcb10c931f33a105e98
Linux amd64 0.5.0 2022-05-12 cw (3.3mo) 7203e4facfd82f54501ff17b569055daf7856164ed71a66b3fbfbe8dd9633293
Windows amd64 0.5.0 2022-05-12 cw.exe (3.4mo) 2278d95d28011cbd2b97aed08e5e73274f08d245092cab58ac7f9d5c772e6892

When downloaded, you can check that the executable isn't compromised by comparing the SHA checksum you get by running the following command and the value displayed in the previous table.

$ shasum -a 256 ./cw 
b35078644ac3b3f025276a0c5fcd77b3d2c8fe9cd15d136df969772e6f513973  ./cw

On Linux and macOS, give the executable permission to the file:

$ chmod +x ./cw

If you need another executable type, create an issue and point out the operating system/target platform you want, you will find the possible values in this article.

For convenience, add cw in your path so you can access it from everywhere.

πŸ’‘ The executable is "quite" big (several mo) because it includes the Go run-time and doesn't have external dependencies.

Running the watcher ⚑

Now that you have built or downloaded the program, let's try it. If you run it without arguments, it displays the help message. If you are at the root of your Symfony application, you can start to watch your project files with the following command:

$ cw .

You should have the following output:

β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
  CacheWatcher version v0.5.1 by COil - https://www.strangebuzz.com 🐝
β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
CacheWatcher watches your files (.env, YAML, Twig) and automatically refreshes your application cache.
β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
 > Project directory: /Users/coil/Sites/strangebuzz.com
 > Symfony console path: bin/console
 > Symfony env: Symfony 5.4.8 (env: dev, debug: true)
 > 400 file(s) watched in /Users/coil/Sites/strangebuzz.com in 6 millisecond(s).
 > CTRL+C to stop watching or run kill -9 7817.

That's it! If you have a Symfony 4 or 5 project with the Flex directory structure, it's everything you need.

When a change will be detected in your services.yaml file, for example, you will get the following feedback:

⬇ Update detected at 17:09:03 > refreshing cache...
  βœ…  Done! in 2.43 second(s).

Now refresh your page. It should be "fast" as the cache is already refreshed: 🐰

Cache already loaded

Instead of having a "slow" page: 🐌

Cache refreshed by the browser call

πŸ’‘ You can also pass a relative path or an absolute path for the argument:

$ cw ../strangebuzz.com
$ cw /Users/coil/Sites/strangebuzz.com 

I run it in the PHPStorm included terminal:

Using cw inside a PHPStorn terminal

/‼️\ Be careful that when closing the PHPStorm window, the cw process won't be automatically be killed. /‼️\

Stopping the watcher β›”

You can either press CTRL+C or run the kill command with the PID the program has displayed in the welcome message:

$ kill -9 28157

Configuration πŸŽ›οΈ

As we saw previously, if your project has the Flex directory structure, the default settings should be OK. The default values will always be set for the last minor Symfony version, currently 5.4:

Key Default value Description
console_path bin/console Relative path to the Symfony console
env dev This is the APP_ENV parameter
debug true This is the APP_DEBUG parameter (true or false)
config_dir config Relative directory where are stored the configuration files
translations_dir translations Relative directory where are stored the translations files
templates_dir templates Relative directory where are stored the templates files
entities_dir src/Entity Relative directory where are stored the Doctrine entities
templates_extension twig Default extension for templates files
yaml_extension yaml Default extension for YAML files, we consider it must be consistent within the application
php_extension php Default extension for PHP files, we consider it must be consistent within the application
sleep_time 30 Sleep time between two filesystem checks in milliseconds

If you are not using Flex, you can put a .cw.yaml file at the root of your project. Here is the configuration I use for one of my "old" Symfony 4.4 projects:

config_dir:       app/config
translations_dir: src/AppBundle/Resources/translations
templates_dir:    src/AppBundle/Resources/views
entities_dir:     src/AppBundle/Entity
yaml_extension:   yml
sleep_time:       30

πŸ’‘ The sleep time is the parameter in milliseconds between two filesystem checks. The lower it is, the faster the cache will be refreshed, but the higher the CPU will be used. I found 30 ms to be a good value for my MacMini 2018 (i7/3,2GHz/16go), but you probably want to find the best value for your system (with top or htop).

Todo πŸ“‹

Contributing 🀝

You are welcome. But don't forget that I want to keep this program very light with a unique feature. Even it's very young; it's almost "feature complete".

Fun fact (or not) πŸ˜„

When I developed cw, I played a lot with configuration files. One time, I modified my .env file. And it turns out that when I refreshed the browser, the page was "fast", like 50ms. I repeated the process several times, the same result! πŸ€” It took me some time to realize that an cw process was still running in the background! That's why I couldn't see the "slow" timer. That was it; I had my proof; it works! β„’ 😊

Credits β„’

License β„’

This software is published under the MIT License.

Thanks πŸ‘

Changelog πŸ“’

V0.5.1

  • Added Darwin arm64 executable (For Apple M1 family)

V0.5.0

  • Added support to watch Doctrine entities (useful for API Platform)

V0.4.0

  • Initial version

Conclusion

When I wrote this blog post, using Cw gave me a feeling of smoothness. For sure, it makes my developer experience better πŸ™. Will it be the case for you? I hope you will give it a try πŸ˜‰.

That's it! I hope you like it. Check out the links below to have additional information related to the post. As always, feedback, likes and retweets are welcome. (see the box below) See you! COil. 😊

  Read the doc   Contribute   Download

  Work with me!


Call to action

Did you like this post? You can help me back in several ways: (use the Tweet on the right to comment or to contact me )

Thank you for reading! And see you soon on Strangebuzz! πŸ˜‰

COil