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).
I will assume you have a basic knowledge of Symfony and the commands related to the cache.
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
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 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).
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.
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 email@example.com:strangebuzz/cache-watcher.git $ cd cache-watcher $ make build
It will build the
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|
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: 🐰
Instead of having a "slow" page: 🐌
💡 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:
/‼️\ 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
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:
|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).
- [ ] Add CI with GitHub actions
- [ ] Add an option to display the watched files
- [ ] Allow having an additional whitelist of custom files to watch
- [ ] Feel free to create an issue ➕.
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
.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!
- Symfony ™ is a trademark of Symfony SAS.
- Logo by Claire Brunaud.
- Original Golang logo "Gopher" by Renee French.
This software is published under the MIT License.
- Jonathan Scheiber for his many documentation and blog posts proofreadings.
- Added Darwin arm64 executable (For Apple M1 family)
- Added support to watch Doctrine entities (useful for API Platform)
- Initial version
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. 😊
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 )
- Report any error/typo.
- Report something that could be improved.
- Like and retweet!
- Follow me on Twitter Follow me on Twitter
- Subscribe to the RSS feed.
- Click on the More on Stackoverflow buttons to make me win "Announcer" badges 🏅.
Thank you for reading! And see you soon on Strangebuzz! 😉