Obviously, such an approach can be justified by noting Moore’s Law and the ever decreasing cost of hardware and bandwidth coupled with the argument that development groups can just leverage their existing enterprise development patterns and practices. What is often overlooked is the associated help desk and remote management costs as well as the deployment and field support costs associated with supporting datacenter-like infrastructures remotely. Whereas remote-site applications used to be designed to run in a lights-out production environment; now, much product development takes a “lazy” approach and just adds layers of management software and remote monitoring. These are, however, real costs that must be borne by the customer — probably in excess of having a resilient solution designed for minimum configuration management and support. This is one area that the Go programming language is uniquely positioned to help address: simplifying the delivery of service-based applications in remote business environments.
One common challenge when supporting applications deployed in remote locations — i.e., outside of a managed datacenter environment — is network configuration management. Deploying network applications typically requires that servers, workstations and devices be deployed with static iP configurations, and if we have multiple remote locations, say, several thousand or more, with different device requirements, considerable effort can be spent developing and managing network IP address schemes. One work-around to this problem involves using IP multicast and requiring the applications and services to find each other through the multicast pool; while this works, implementing this is definitely a distraction from getting on with the business of writing business logic and delivering functionality.
Ideally, we’d like to be able to simplify network configuration — say, use default DHCP services — and let the application loop through a prescribed range of addresses in order to find the particular service of interest. The only problem is that if we just try looping through candidate IP addresses using Dial(), we’ll end with long latencies while the application blocks waiting for net.Dial() to timeout.
Go allows us to build and deploy compact service-based applications. For services-based applications deployed to remote computing environments, I would like to minimize dependencies on hardware and network configuration as much as possible. Essentially, I’d like to be able to deploy solutions that are self configuring on a minimal infrastructure. Using goroutines and channels we can wrap the relevant Dial() function and let the application loop through the candidate addresses using a specified timeout period so that the application isn’t blocking for the TCP/IP timeout. The basic programming pattern has been discussed by Andrew Gerrard in the Go Programming Language Blog; here I’ll apply the pattern to testing whether a websocket connection can be established.
The idiomatic Go pattern for testing to see if we can establish a websocket connection on a specific IP addresses should be:
- wrap the websocket.Dial() function in a function, say, ‘dialWebsocConn()’, that passes the websocket.Dial() return values on a channel;
- after invoking ‘dialWebsocConn()’ as a go routine, the calling function, say, ‘GetWebsocConn()’, enters a timing loop that repeatedly checks the channel for the Dial() result until the prescribed time interval expires;
- if the prescribed time has expired, then assume the connection cannot be established — close the channel and return a relevant error value so that the application can continue, perhaps trying another address on the network.
Some code to implement this pattern is as follows.