Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pubsub: default autoCreate:true #685

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,13 +214,11 @@ var pubsub = gcloud.pubsub({
keyFilename: '/path/to/keyfile.json'
});

// Create a new topic.
pubsub.createTopic('my-new-topic', function(err, topic) {});

// Reference an existing topic.
var topic = pubsub.topic('my-existing-topic');
// Reference a topic.
var topic = pubsub.topic('my-topic');

This comment was marked as spam.


// Publish a message to the topic.

This comment was marked as spam.

This comment was marked as spam.

// The topic will be created if it doesn't exist.

This comment was marked as spam.

topic.publish({
data: 'New message!'
}, function(err) {});
Expand Down
44 changes: 39 additions & 5 deletions lib/pubsub/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,16 @@ PubSub.prototype.getTopics = function(query, callback) {
*
* @example
* pubsub.createTopic('my-new-topic', function(err, topic, apiResponse) {
* topic.publish('New message!', function(err) {});
* topic.publish({

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

* data: 'New message!'
* }, function(err) {});
* });
*
* //-
* // <strong>Note:</strong> For cases like the one above, it is simpler to use
* // {module:pubsub#topic}, which will create the topic for you at the time you
* // publish a message.
* //-

This comment was marked as spam.

This comment was marked as spam.

*/
PubSub.prototype.createTopic = function(name, callback) {
callback = callback || util.noop;
Expand Down Expand Up @@ -315,14 +323,40 @@ PubSub.prototype.subscription = function(name, options) {
*
* @param {string} name - The name of the topic.
* @param {object=} options - Configuration object.
* @param {boolean=} options.autoCreate - Automatically create topic if it
* @param {boolean} options.autoCreate - Automatically create topic if it
* doesn't exist. Note that messages published to a topic with no
* subscribers will not be delivered.
* subscribers will not be delivered. Default: true.
* @return {module:pubsub/topic}
*
* @example
* var topic = pubsub.topic('my-existing-topic');
* var topic = pubsub.topic('topic-that-maybe-exists', { autoCreate: true });
* //-
* // By default, it isn't required to specify a topic that already exists. The
* // first time you publish a message, the topic will be created for you.
* //
* // This will only cost one additional API request at the time of publishing.
* // If the topic doesn't need to be created, there is no performance penalty.
* //-
* var topic = pubsub.topic('my-topic');
*
* topic.publish({
* data: 'New message!'
* }, function(err) {});
*
* //-
* // If you prefer an error when trying to publish to a topic that doesn't
* // exist, set `autoCreate` to `false`.
* //-
* var nonExistentTopic = pubsub.topic('my-non-existent-topic', {
* autoCreate: false
* });
*
* nonExistentTopic.publish({
* data: 'New message!'
* }, function(err) {
* if (err) {
* // API error from trying to publish a message to a non-existent topic.
* }
* });

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

*/
PubSub.prototype.topic = function(name, options) {
if (!name) {
Expand Down
6 changes: 3 additions & 3 deletions lib/pubsub/subscription.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,23 +76,23 @@ var util = require('../common/util.js');
* //-
* // From {@linkcode module:pubsub/topic#getSubscriptions}:
* //-
* var topic = pubsub.topic('my-existing-topic');
* var topic = pubsub.topic('my-topic');
* topic.getSubscriptions(function(err, subscriptions) {
* // `subscriptions` is an array of Subscription objects.
* });
*
* //-
* // From {@linkcode module:pubsub/topic#subscribe}:
* //-
* var topic = pubsub.topic('my-existing-topic');
* var topic = pubsub.topic('my-topic');
* topic.subscribe('new-subscription', function(err, subscription) {
* // `subscription` is a Subscription object.
* });
*
* //-
* // From {@linkcode module:pubsub/topic#subscription}:
* //-
* var topic = pubsub.topic('my-existing-topic');
* var topic = pubsub.topic('my-topic');
* var subscription = topic.subscription('my-existing-subscription');
* // `subscription` is a Subscription object.
*
Expand Down
91 changes: 45 additions & 46 deletions lib/pubsub/topic.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ var util = require('../common/util.js');
*
* @param {module:pubsub} pubsub - PubSub object.
* @param {object} options - Configuration object.
* @param {boolean=} options.autoCreate - Automatically create topic if it
* doesn't exist. Note that messages published to a topic with no
* subscribers will not be delivered. Default: true.
* @param {string} options.name - Name of the topic.
*/
/**
* A Topic object allows you to interact with a Google Cloud Pub/Sub topic. To
* get this object, you will use the methods on the `pubsub` object,
* {@linkcode module:pubsub#topic} and {@linkcode module:pubsub#createTopic}.
* A Topic object allows you to interact with a Google Cloud Pub/Sub topic.
*
* @constructor
* @alias module:pubsub/topic
Expand All @@ -45,25 +46,15 @@ var util = require('../common/util.js');
* projectId: 'grape-spaceship-123'
* });
*
* // From pubsub.topic:
* var topic = pubsub.topic('my-existing-topic');
*
* // From pubsub.createTopic:
* pubsub.createTopic('my-new-topic', function(err, topic) {
* // `topic` is a Topic object.
* });
* var topic = pubsub.topic('my-topic');
*/
function Topic(pubsub, options) {
this.makeReq_ = pubsub.makeReq_.bind(pubsub);
this.autoCreate = options.autoCreate !== false;
this.name = Topic.formatName_(pubsub.projectId, options.name);

this.projectId = pubsub.projectId;
this.pubsub = pubsub;
this.unformattedName = options.name;

if (options.autoCreate) {
this.origMakeReq_ = this.makeReq_;
this.makeReq_ = this.autoCreateWrapper_;
}
}

/**
Expand Down Expand Up @@ -99,34 +90,6 @@ Topic.formatName_ = function(projectId, name) {
return 'projects/' + projectId + '/topics/' + name;
};

/**
* Wrapper for makeReq_ that automatically attempts to create a topic if it does
* not yet exist.
*
* @private
*/
Topic.prototype.autoCreateWrapper_ = function(method, path, q, body, callback) {
var self = this;

function createAndRetry() {
self.pubsub.createTopic(self.unformattedName, function(err) {
if (err) {
callback(err);
return;
}
self.origMakeReq_(method, path, q, body, callback);
});
}

this.origMakeReq_(method, path, q, body, function(err, res) {
if (err && err.code === 404 && method !== 'DELETE') {
createAndRetry();
} else {
callback(err, res);
}
});
};

/**
* Publish the provided message or array of messages. On success, an array of
* messageIds is returned in the response.
Expand All @@ -144,7 +107,7 @@ Topic.prototype.autoCreateWrapper_ = function(method, path, q, body, callback) {
* topic.publish({
* data: 'Hello, world!'
* }, function(err, messageIds, apiResponse) {});
*
*
* //-
* // The data property can be a JSON object as well.
* //-
Expand All @@ -159,7 +122,7 @@ Topic.prototype.autoCreateWrapper_ = function(method, path, q, body, callback) {
* hello: 'world'
* }
* };
*
*
* topic.publish(registerMessage, function(err, messageIds, apiResponse) {});
*
* //-
Expand Down Expand Up @@ -321,4 +284,40 @@ Topic.prototype.subscription = function(name, options) {
return this.pubsub.subscription(name, options);
};

/**
* Make an API request using the parent PubSub object's `makeReq_`. If the Topic
* instance has `autoCreate: true` set, this method will first try to create the
* Topic in the event of a 404.
*
* @private
*
* @param {string} method - Action.
* @param {string} path - Request path.
* @param {*} query - Request query object.
* @param {*} body - Request body contents.
* @param {function} callback - The callback function.
*/
Topic.prototype.makeReq_ = function(method, path, query, body, callback) {
var self = this;

function createTopicThenRetryRequest() {
self.pubsub.createTopic(self.unformattedName, function(err, topic, res) {
if (err) {
callback(err, null, res);
return;
}

self.pubsub.makeReq_(method, path, query, body, callback);
});
}

this.pubsub.makeReq_(method, path, query, body, function(err, res) {
if (self.autoCreate && err && err.code === 404 && method !== 'DELETE') {
createTopicThenRetryRequest();
} else {
callback(err, res);
}
});
};

module.exports = Topic;
20 changes: 19 additions & 1 deletion system-test/pubsub.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ describe('pubsub', function() {
});

describe('Topic', function() {

it('should be listed', function(done) {
pubsub.getTopics(function(err, topics) {
assert.ifError(err);
Expand Down Expand Up @@ -98,6 +97,25 @@ describe('pubsub', function() {
});
});

it('should lazily create by default', function(done) {
var newTopicName = generateTopicName();
var newTopic = pubsub.topic(newTopicName);

newTopic.publish({ data: 'message from me' }, function(err) {
assert.ifError(err);

pubsub.getTopics(function(err, topics) {
assert.ifError(err);

assert(topics.some(function(topic) {
return topic.name.indexOf(newTopicName) > -1;
}));

newTopic.delete(done);
});
});
});

it('should publish a message', function(done) {
var topic = pubsub.topic(TOPIC_NAMES[0]);
topic.publish({ data: 'message from me' }, function(err, messageIds) {
Expand Down
Loading