How does an application configure its database connection? I find this to be a pretty interesting question. As the application moves from a developer’s workstation to a test harness, then to staging, and on to production, the database connection properties can change each time. What’s more, a separation of responsibilities usually falls between the developers creating application code and the operations staff running those environments. The database connection properties fall in the interface between those two groups.
Each group wants clearly distinguished roles, and one of my personal goals with Database Jones is to keep that interface clean. Jones encapsulates the operations side in a single file called jones_deployments.js. A Jones application developer works with the Jones APIs such as Session and Query, but the operations staff managing that application should rarely need to look beyond the jones_deployments file.
What is a deployment?
Technically, a deployment is a function that takes a set of ConnectionProperties and possibly modifies them. The application developer, though, should most likely supply just the name of the deployment – as a string – to the Jones ConnectionProperties() constructor, like this:
1
2
3
4
|
/* adapter: name of the backend database service provider, e.g. mysql or ndb deployment: name of a deployment defined in jones_deployments.js */ var properties = new Jones.ConnectionProperties(adapter, deployment); |
The deployment itself will be found in jones_deployments.js. Once you obtain the connection properties, you can use them in an openSession() or connect() call:
1 |
jones.openSession(properties).then( ... ) |
Here are the actual steps followed by the ConnectionProperties constructor.
- Obtain the default connection properties for adapter. These by convention are defined in jones-adapter/DefaultConnectionProperties.js, as you can see in the github repos for jones-mysql and jones-ndb.
- Clone the properties so that the user gets a distinct copy.
- Search the deployment search path for a jones_deployments.js file that contains a function matching the named deployment. If the function is found, it is called with the ConnectionProperties as its argument; otherwise an AssertionError is thrown.
- Return the ConnectionProperties to the user.
To the systems administrator, each deployment in jones_deployments provides the full power of JavaScript and node.js toward configuration problems. For a simple example, every build of Jones is tested in Hudson, and our Hudson job relies on environment variables to describe the database connection. We configure the test scripts to use a deployment named test, defined here. If PORT_SQL1 is set in the environment, test overrides the default connection properties; otherwise it passes them through unchanged.
1
2
3
4
5
6
7
8
|
deployments.test = function(properties) { if(process.env["PORT_SQL1"]) { properties.mysql_host = process.env["HOSTNAME"]; properties.mysql_port = process.env["PORT_SQL1"]; properties.ndb_connectstring = process.env["HOSTNAME"] + ":" + process.env["PORT_MGMD"]; } }; |
The deployments search path
To find jones_deployments files, Jones searches in this order:
- Look in the same directory as the main JavaScript executable file.
- Walk the chain of required modules from the main script towards jones.js.
- Walk the filesystem tree from the main script to the root directory.
- Look in the current working directory, unless it was added to the search path in one of the previous steps.
If that description seems imprecise, the good news is that Jones can tell you the exact search path, using its runtime statistics API, at the statistics path /api/deployments/searchPath. Here’s a complete example starting from nothing:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
% npm install database-jones jones-mysql % node > var jones = require("database-jones"); > jones.stats.query(["api","deployments","searchPath"]); [ '/Users/jdd/tmp/workshop', '/Users/jdd/node_modules/database-jones/Adapter/api', '/Users/jdd/tmp', '/Users/jdd', '/Users', '/' ] |
The ConnectionProperties constructor also uses another statistic, /api/deployments/resolved, to record the actual pathname to the jones_deployments file used to resolve a named deployment.
I hope this design helps teams work together easily to build and deploy applications.