Wednesday, July 8, 2015

SSH connection drop issue for Ubuntu virtualbox guest on Windows 7 host with NAT network

The problem was really annoying when I need to ssh to some Linux servers from the Ubuntu virtualbox guest. As I remember, it started after I updated the VirtualBox platform to 4.3.26 or updated the guest from 12.04 to 14.04. The fix was surprisingly simple. See https://forums.virtualbox.org/viewtopic.php?f=6&t=66086#p313103

With the default Intel adapter, ssh connections were always dropped. When switching to the first non-Intel adapter, the issue was gone. 

Thursday, April 30, 2015

Update twitter typeahead to 0.11

Overall, I think the bloodhound/typeahead's API gets much better from 0.10 to 0.11. The limit option was moved from bloodhound to typeahead because it is more related to display than indexing and query. The DOM element classes were changed, and I update the styles after reading the www.js file. The javascript and CSS code is on gist.





Sunday, March 29, 2015

Macbook power problem and GFCI outlet

This was what I experienced a while ago. I worked on my macbook on the dinner table, and plugged the power adapter to the closest wall outlet in the kitchen. In a few minutes, I noticed that the battery percentage turned very low. It was not charging at all, but discharging. I turned the macbook around, and found the back was really hot. I then shut it down.

I asked Google what could be the problem, and found this. I followed the instruction to reset SMC. But it did not solve the problem.

I found the outlet was a GFCI outlet. It has a green led and two buttons. I suspected the outlet could be the problem, and plug the power adapter to a normal outlet. The problem was fixed. I still do not know if it was caused by that outlet, or all GFCI outlets are not safe for the macbook adapter.

Tuesday, March 17, 2015

request.get(...).pipe(response) is not RESTful

Request is a nice package for HTTP client programming on node.js. It provides API's that can directly stream. So you can do things like
request('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'))
When programming a service proxy, it is straightforward to do something like
app.get('/proxied/service', function (req, res) {
    request.get('http://the/real/service').pipe(res);
})
It is so neat and powerful. However, it is not RESTful, and in some cases it could cause errors that is hard to figure out. When the client of the proxied service gets the response, it always expects some representation from your service not the real service. When the representation of 'http://the/real/service' was sent to the client, the client will be confused. For example, the authorization header, the cache-control header, or the cookie header can all have side effects.

In an application I develop, I had a proxied service just like the above. It provided a list in JSON that was fetched from the other service hosted by a different application. It ran well in test and first a few month after released, until one day a user complained that he cannot access the list that should appear in the suggestion of a text input. I found the service was down. However, the user should still be able to type in whatever s/he thought was right, and then save it on the application. But the issue was that the application rejects such a request for authentication reason if the user's hand was not quick enough.  It took me a while trying to reproduce the problem on my browser, and then figure it out.

The problem was that the remote service was down, and the client's browser got a "net::ERR_EMPTY_RESPONSE" error that basically means the server closed the connection without sending any data. That was only first half of the story. Such an error will force the browser to clean up the cookies set by the application, and all following requests from the same page will be rejected. So the proper way is still to provide a timeout, and an error handler like
   request({
      url: service.device.url,
      timeout: 30 * 1000,
      ...
    }, function (err, response, resBody) {
      if (err) {
        return res.json(503, ...);
      }
     ...
    });

500, 502, 503 are good codes for this case.

Wednesday, February 4, 2015

Bootstrap progress bar with markers and labels

Here is a gist to generate a progress bar with markers and labels. It results a progress bar like the following.


The code snippets are on github. It is based on an answer on stackoverflow.

Sunday, February 1, 2015

Shipping status checking and its implementations

It is the holiday season, and everyone hopes their shippings arrive on time. Checking shipping status is a basic service for online retailers. For the two largest retailers, checking shipping status is implemented as a service that returns a block of HTML including JavaScript. I assume the main rationale behind this design is the easiness for front end integration. So the implementation is a typical server-side mashup. The user clicks on the link/button, the request is sent to the mashup service, the mashup service sends a request or several requests to the shipping carrier services, then the mashup service generates the HTML snippet and sends it back. At the same time, the mashup service can log the data from both the user and the carrier services.

There must be more details in the real implementation. One interesting aspect is the carrier API's Service Level Agreement (SLA). Request throttling policy is one of the most critical pieces in SLA. A carrier service normally restricts the maximum number of service request from a client in a sliding time window and the maximum request rate, and some even have penalties (not just refusing the requests) if the client violates the restrictions. This can make the retailer's mashup service complicate when it tries to behave nicely in the face of a carrier's service and fulfills large amount of user requests.

There is an easier solution other than the server-side mashup approach. If the carrier's service allows cross-origin resource sharing, a client-side mashup can be implemented. Or simply a link to the carrier website with the tracking number in URL will work. What if the retailer wants to track the clicks? Then a link hosted by the retailer with the carrier's link encoded in the query like those in Google search results will work.