Permalink
Browse files

Merge branch 'release/0.3.0'

  • Loading branch information...
2 parents 7258b64 + 1a94592 commit 2bb6189edb9bd801d4fbad966ea14787b8cb7455 @smith smith committed May 3, 2011
Showing with 233 additions and 37 deletions.
  1. +1 −0 .gitignore
  2. +4 −0 HISTORY.md
  3. +22 −1 README.md
  4. +12 −9 lib/client.js
  5. +11 −1 lib/client/responses.js
  6. +3 −7 lib/gearman.js
  7. +13 −0 lib/job.js
  8. +7 −1 lib/packet/requests.js
  9. +28 −7 lib/packet/responses.js
  10. +5 −0 lib/packet/types.js
  11. +1 −1 package.json
  12. +26 −4 test/test-client.js
  13. +51 −2 test/test-job.js
  14. +49 −4 test/test-packet.js
View
@@ -0,0 +1 @@
+node_modules
View
@@ -1,5 +1,9 @@
# History
+## 0.3.0 / 2011-05-02
+
+* Background job support
+
## 0.2.0 / 2011-04-15
* Foreground job priority support
View
@@ -62,12 +62,19 @@ Submits a job to a manager and returns a `gearman.Job`. `data` defaults to a `Bu
`options` is an object with the following defaults:
- { priority: 'normal',
+ { background: false,
+ priority: 'normal',
encoding: null
}
`priority` can be one of `'low'`, `'normal'`, or `'high'`.
+If `background` is set to `true`, the job is detached after the `create` event and no further events are emitted.
+
+#### client.getJobStatus(handle, [callback])
+
+Works the same as `job.getStatus` but takes a job handle (assigned previously by the server for a job submitted with `background: true`) and executes a callback taking an object with status information.
+
### gearman.Job
An object representing a job that has been submitted. `gearman.Job` instances are EventEmitters with the these events:
@@ -102,6 +109,20 @@ Emitted when a job completes. `data` is the data sent, as a `Buffer` or as a Str
Emitted when a job fails.
+#### job.getStatus([callback])
+
+For a job that was submitted in the background (with `background: true`), get information about its status. `callback` will be called when the server returns the status, with an object showing status information:
+
+ job.getStatus(function (status) { console.dir(status); });
+
+The `status` object returned can contain the following:
+
+ { handle: String, // the job's handle
+ known: Boolean, // is the job known?
+ running: Boolean, // is the job running?
+ percentComplete: [Number, Number] // Numerator & denominator of percentage complete
+ }
+
## Tests
To run the tests:
View
@@ -30,22 +30,14 @@ Client.prototype.getConnection = function () {
if (!conn) {
conn = net.createConnection(this.port, this.host);
- conn.on("connect", function () {
- client.connected = true;
- });
-
- conn.on("close", function (error) {
- client.connected = false;
- });
-
conn.on("data", function (data) {
// decode the data and execute the proper response handler
data = packet.decode(data);
var type = data.type;
debug("Recieved:", data);
if (type in responses) { responses[type](data, client); }
});
- } else if (!client.connected) { conn.connect(this.port, this.host); }
+ }
this.connection = conn;
return conn;
@@ -69,3 +61,14 @@ Client.prototype.submitJob = function (name, data, options) {
job.submit();
return job;
};
+
+// Get a job's status from its handle
+Client.prototype.getJobStatus = function (handle, callback) {
+ var job = this.jobs[handle];
+
+ // If we don't have the job, create it
+ if (!job) {
+ job = new Job({ client: this, handle: handle, background: true });
+ }
+ job.getStatus(callback);
+};
View
@@ -27,5 +27,15 @@ module.exports = {
job.emit("fail");
},
WORK_DATA: jobEmitData("data"),
- WORK_WARNING: jobEmitData("warning")
+ WORK_WARNING: jobEmitData("warning"),
+ // Get a STATUS_RES response, find the jobs, and execute their callbacks
+ STATUS_RES: function (data, client) {
+ data = data || {};
+ var job = client.jobs[data.handle];
+ delete data.type;
+
+ if (job) { job.statusCallbacks.forEach(function (callback) {
+ callback(data);
+ }); }
+ }
};
View
@@ -1,9 +1,5 @@
-var Client = require("./client").Client,
- Job = require("./job").Job;
+var Client = require("./client").Client;
exports.Client = Client;
-exports.Job = Job;
-
-exports.createClient = function (port, host) {
- return new Client(port, host);
-};
+exports.Job = require("./job").Job;
+exports.createClient = function (port, host) { return new Client(port, host); };
View
@@ -13,6 +13,9 @@ Job = function (options) {
extend(this, options);
this.client = this.client || gearman.createClient();
this.priority = this.priority || "normal";
+
+ // Array of callbacks waiting for status
+ this.statusCallbacks = [];
};
inherits(Job, EventEmitter);
exports.Job = Job;
@@ -29,7 +32,17 @@ Job.prototype.submit = function () {
if (!(this.priority in priorities)) { throw Error("invalid priority"); }
data.type = priorities[this.priority];
+ // Append _BG to background jobs' type
+ if (this.background) { data.type += "_BG"; }
+
client.getConnection().write(packet.encode(data), this.encoding);
debug("Sent:", data);
client.lastJobSubmitted = this;
};
+
+Job.prototype.getStatus = function (callback) {
+ var data = { type: "GET_STATUS", handle: this.handle };
+ this.client.getConnection().write(packet.encode(data));
+ debug("Sent:", data);
+ if (typeof callback === "function") {this.statusCallbacks.push(callback); }
+};
View
@@ -28,5 +28,11 @@ function submitJob(options) {
module.exports = {
SUBMIT_JOB: submitJob,
SUBMIT_JOB_HIGH: submitJob,
- SUBMIT_JOB_LOW: submitJob
+ SUBMIT_JOB_LOW: submitJob,
+ SUBMIT_JOB_BG: submitJob,
+ SUBMIT_JOB_HIGH_BG: submitJob,
+ SUBMIT_JOB_LOW_BG: submitJob,
+ GET_STATUS: function (options) {
+ return new Buffer((options || {}).handle, "ascii");
+ }
};
View
@@ -1,6 +1,8 @@
// functions used for multiple response types
-var binary = require("binary");
+var binary = require("binary"),
+ extend = require("../util").extend,
+ nb = new Buffer([0]); // null buffer
function resHandle(object) {
object = object || {};
@@ -18,17 +20,17 @@ function resHandleAndData(object) {
size = 0;
o = binary.parse(data).
- scan("handle", new Buffer([0])).
+ scan("handle", nb).
tap(function (vars) {
size = data.length - vars.handle.length - 1;
}).
buffer("data", size).
vars;
- object.handle = o.handle.toString();
- object.data = o.data;
-
- return object;
+ return extend({
+ handle: o.handle.toString(),
+ data: o.data
+ }, object);
}
module.exports = {
@@ -37,5 +39,24 @@ module.exports = {
WORK_FAIL: resHandle,
WORK_EXCEPTION: resHandleAndData,
WORK_DATA: resHandleAndData,
- WORK_WARNING: resHandleAndData
+ WORK_WARNING: resHandleAndData,
+ STATUS_RES: function (object) {
+ object = object || {};
+ var o = {};
+
+ o = binary.parse(object.inputData).
+ scan("handle", nb).
+ scan("known", nb).
+ scan("running", nb).
+ scan("num", nb).
+ word8be("den").
+ vars;
+
+ return extend({
+ handle: o.handle.toString(),
+ known: !!o.known[0],
+ running: !!o.running[0],
+ percentComplete: [o.num[0], o.den]
+ }, object);
+ }
};
View
@@ -2,6 +2,11 @@ exports.names = {
SUBMIT_JOB: 7,
SUBMIT_JOB_HIGH: 21,
SUBMIT_JOB_LOW: 33,
+ SUBMIT_JOB_BG: 18,
+ SUBMIT_JOB_HIGH_BG: 32,
+ SUBMIT_JOB_LOW_BG: 34,
+ GET_STATUS: 15,
+ STATUS_RES: 20,
JOB_CREATED: 8,
WORK_COMPLETE: 13,
WORK_FAIL: 14,
View
@@ -1,6 +1,6 @@
{
"name": "gearman",
- "version": "0.2.0",
+ "version": "0.3.0",
"description": "Client library for Gearman",
"keywords": ["gearman", "job", "worker", "background"],
"homepage": "https://github.com/cramerdev/gearman-node",
View
@@ -3,19 +3,25 @@ var gearman = require("gearman"),
Job = gearman.Job,
Socket = require("net").Socket,
testCase = require("nodeunit").testCase,
- client = gearman.createClient();
+ client;
+
+// gearman.debug = true;
+
+client = gearman.createClient();
module.exports = testCase({
"createClient": function (test) {
+ var otherClient;
+
test.ok(client instanceof Client,
"gearman.createClient() creates a client");
test.equal(client.port, 4730, "default port 4730");
test.equal(client.host, "localhost", "default host 'localhost'");
- client = gearman.createClient(1234, "example.com");
+ otherClient = gearman.createClient(1234, "example.com");
- test.equal(client.port, 1234, "port argument 1234");
- test.equal(client.host, "example.com", "host argument 'example.com'");
+ test.equal(otherClient.port, 1234, "port argument 1234");
+ test.equal(otherClient.host, "example.com", "host argument 'example.com'");
test.done();
},
@@ -36,5 +42,21 @@ module.exports = testCase({
test.ok(typeof client.end === "function",
"client.end() method exists");
test.done();
+ },
+
+ "getJobStatus": function (test) {
+ var job = client.submitJob("test", "test", { background: true });
+ test.ok(typeof client.getJobStatus === "function",
+ "client.getJobStatus is a function");
+
+ job.on("create", function (handle) {
+ client.getJobStatus(handle, function (status) {
+ test.deepEqual(status, { handle: handle,
+ known: true,
+ running: true,
+ percentComplete: [ 48, 48 ] });
+ test.done();
+ });
+ });
}
});
View
@@ -2,12 +2,16 @@ var gearman = require("gearman"),
Job = gearman.Job,
EventEmitter = require("events").EventEmitter,
testCase = require("nodeunit").testCase,
- client = gearman.createClient(),
- job = client.submitJob("test", "test", { encoding: "utf8" });
+ client, job;
// XXX: These need a real gearman server running on localhost:4730 and
// test/fixtures/worker.rb running. Need to make a mock server or something.
+// gearman.debug = true;
+
+client = gearman.createClient();
+job = client.submitJob("test", "test", { encoding: "utf8" });
+
module.exports = testCase({
"Job": function (test) {
test.ok(job instanceof EventEmitter,
@@ -58,6 +62,51 @@ module.exports = testCase({
test.done();
},
+ "submit { background: true }": function (test) {
+ var job = client.submitJob("test", "test", { background: true });
+
+ job.on("create", function (handle) {
+ job.getStatus(function (status) {
+ test.deepEqual(status, { handle: handle,
+ known: true,
+ running: true,
+ percentComplete: [ 48, 48 ] });
+ test.done();
+ });
+ });
+ },
+
+ "submit { background: true, priority: 'high' }": function (test) {
+ var job = client.submitJob("test", "test", { background: true,
+ priority: "high" });
+
+ job.on("create", function (handle) {
+ job.getStatus(function (status) {
+ test.deepEqual(status, { handle: handle,
+ known: true,
+ running: true,
+ percentComplete: [ 48, 48 ] });
+ test.done();
+ });
+ });
+ },
+
+ "submit { background: true, priority: 'low' }": function (test) {
+ var job = client.submitJob("test", "test", { background: true,
+ priority: "low" });
+
+ job.on("create", function (handle) {
+ job.getStatus(function (status) {
+ test.deepEqual(status, { handle: handle,
+ known: true,
+ running: true,
+ percentComplete: [ 48, 48 ] });
+ test.done();
+ });
+ });
+ },
+
+
"event: data": function (test) {
job.on("data", function (result) {
test.equal("test", result, "work data received");
Oops, something went wrong.

0 comments on commit 2bb6189

Please sign in to comment.