Chrome LiveReload Extension and Remote Machines

Written by Pete Corey on Nov 5, 2014.

Last night I decided it would be a good idea to join the 21st century and incorporate LiveReload into my frontend workflow. Since I’m already using grunt-contrib-watch to watch my LESS/SASS files, I figured this would be a breeze. grunt-contrib-watch supports LiveReload out of the box! All that was needed was an options block inside of my watch config:

watch: {
    options: {
        livereload: true,

This option spins up a LiveReload server on my dev machine running on port 35729 by default. In order to leverage LiveReload, your client must include the livereload.js script served by this service. This can be done by either manually adding a script tag to your project, or using the Chrome LiveReload extension. I quickly installed the extension, eagerly pressed the LiveReload button and… got an error!

Could not connect to LiveReload server. Please make sure that a compatible LiveReload server is running. (We recommend guard-livereload, until LiveReload 2 comes to your platform.)

Strange. My dev server was running on a VM on, so to verify that the LiveReload server was running I went to in the brower. As expected, I received a JSON response from grunt-contrib-watch’s tinylr server:

    "tinylr": "Welcome",
    "version": "0.0.5"

Very strange. Livereload was running on my dev machine, but the Chrome extension was unable to connect to it. As a sanity check, I decided to forgo connecting with the browser extension and manually added the livereload.js script tag to my project:

<script src=””></script>

After reloading the page, I noticed that it was able to successfully pull down the livereload.js file and LiveReload changes were taking effect.

While this approach worked, I wasn’t satisfied. I wanted to use the browser extension, not manually include the script in my project. I started digging into the plugin to find out what was going on.

The first thing I did was enable “Developer Mode” in the Chrome extensions window. That allowed me to install and enable the Chrome Apps & Extensions Developer Tool. I fired up the Extension Dev Tools, opened the LiveReload console and once again tried to connect to my dev server. The log messages made it clear what was going on:

Connecting to ws://
Haven't received a handshake reply in time, disconnecting.
WebSocket connection to 'ws://' failed: WebSocket is closed before the connection is established.
Web socket error.
Web socket disconnected.

The LiveReload extension was attempting to connect to, not A quick look through global.js shows that host is hardcoded to in the initialize function.

After looking through the github issues for the LiveReload extension project, I found an unmerged pull request from 2013 by Greg Allen that fixed the issue. Bigwave in the comments had built a version of the extension with the fix and released on the app store as RemoteLiveReload. After installing this new extension, my LiveReload setup started working without a hitch. Thanks Greg and Bigwave!

CrossView Fun With CSS

Written by Pete Corey on Nov 2, 2014.

I while ago I stumbled across the CrossView subreddit. I thought the text CrossView images that contained hidden messages were especially cool. So, I decided to try to create one using simple HTML/CSS. The process was really simple. Check out the codepen below, or view it in fullscreen to better see the effect:

See the Pen Cross View Text Test by Pete Corey (@pcorey) on CodePen.

The effect is created by moving specific words on the left text up a couple pixels, and words on the right side down. The greater the offset, the greater emphasis they’re given when crossviewed. For this font and text size, I found that a 4px span worked well.

This could easily be built into a web-based tool to generate text crossview images. I may work on that in the future if there is any interest in that kind of thing.

Laravel Queue's Sleep Contributes to its Timeout

Written by Pete Corey on Oct 23, 2014.

Once again, I was tinkering with my Laravel queues today and I ran into an interesting issue. I have a queue listener running with the following command:

php artisan queue:listen --env=stage --queue="slow-queue"

The jobs that slow-queue processes are infrequent and aren’t very important, so I decided to have the listener sleep for one minute between job checks:

php artisan queue:listen --sleep 60 --env=stage --queue="slow-queue”

I restarted my supervisor daemon and waited a few minutes to verify that everything was working correctly. Unfortunately, everything was not working correctly. All of the jobs being processed by the slow-queue listener were failing with a ProcessTimedOutException:

[2014-10-23 09:51:27] stage.ERROR: exception 'Symfony\Component\Process\Exception\ProcessTimedOutException' with message 'The process ""/usr/bin/php" artisan queue:work  --queue="slow-queue" --delay=0 --memory=128 --sleep=60 --tries=0 --env=stage" exceeded the timeout of 60 seconds.' in /www/
Stack trace:
#0 /www/ Symfony\Component\Process\Process->checkTimeout()
#1 /www/ Symfony\Component\Process\Process->wait()
#2 /www/ Symfony\Component\Process\Process->run(Object(Closure))

My first thought was that the sleep time must be contributing toward the job processes’ timeout counter (which defaults to 60 seconds). To test this thought, I increased the timeout on the listen command to 61 and tried running the jobs again:

php artisan queue:listen --sleep 60 --timeout 61 --env=stage --queue="slow-queue"

Sure enough, it looked like the jobs were completing successfully. As a quick fix to this issue I increased the timeout for slow-queue to 2 minutes:

php artisan queue:listen --sleep 60 --timeout 120 --env=stage --queue="slow-queue"

It seems very strange to me that the sleep time specified in the queue listener would contribute towards it’s timeout time. In my mind, sleep would cause the listen process to wait the specified number of seconds to check for a new job. If there is a new job, that job process would start and its timeout counter would start.

I may be completely misunderstanding what’s happening here, but I went ahead and opened a github issue to either get it fixed or get an answer.