Skip to content

Commit 65cd0ec

Browse files
NickZchris-smith
authored andcommitted
Implement timeout on initNode() (#81)
This implements a timeout option for initNode. initNode will timeout with a rejection if the node is not initialized within the specified number of seconds. If the timeout is negative, then it will keep retrying forever. Also fixed some of the Promise logic in InitNode().
1 parent 04fa4b5 commit 65cd0ec

6 files changed

Lines changed: 63 additions & 22 deletions

File tree

src/index.js

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,27 @@ let rosNode = null;
4343
let pingMasterTimeout = null;
4444

4545
//------------------------------------------------------------------
46-
47-
function _checkMasterHelper(timeout=100) {
48-
const localHelper = (resolve) => {
46+
/**
47+
* @private
48+
* Helper function to see if the master is available and able to accept
49+
* connections.
50+
* @param {number} timeout time in ms between connection attempts
51+
* @param {number} maxTimeout maximum time in ms to retry before timing out.
52+
* A negative number will make it retry forever. 0 will only make one attempt
53+
* before timing out.
54+
*/
55+
function _checkMasterHelper(timeout=100, maxTimeout=-1) {
56+
let startTime = Date.now();
57+
const localHelper = (resolve,reject) => {
4958
pingMasterTimeout = setTimeout(() => {
50-
// also check that the slave api server is set up
59+
// also check that the slave api server is set up
5160
if (!rosNode.slaveApiSetupComplete()) {
52-
localHelper(resolve);
61+
if (Date.now() - startTime >= maxTimeout && !(maxTimeout < 0) ) {
62+
log.error(`Unable to register with master node [${rosNode.getRosMasterUri()}]: unable to set up slave API Server. Stopping...`);
63+
reject(Error('Unable to setup slave API server.'));
64+
return;
65+
}
66+
localHelper(resolve, reject);
5367
return;
5468
}
5569
rosNode.getMasterUri({ maxAttempts: 1 })
@@ -59,14 +73,20 @@ function _checkMasterHelper(timeout=100) {
5973
resolve();
6074
})
6175
.catch((err, resp) => {
62-
log.warnThrottle(60000, `Unable to register with master node [${rosNode.getRosMasterUri()}]: master may not be running yet. Will keep trying.`);
63-
localHelper(resolve);
76+
if (Date.now() - startTime >= maxTimeout && !(maxTimeout < 0) ){
77+
log.error(`Timed out before registering with master node [${rosNode.getRosMasterUri()}]: master may not be running yet.`);
78+
reject(Error('Registration with master timed out.'));
79+
return;
80+
} else {
81+
log.warnThrottle(60000, `Unable to register with master node [${rosNode.getRosMasterUri()}]: master may not be running yet. Will keep trying.`);
82+
localHelper(resolve, reject);
83+
}
6484
});
6585
}, timeout);
6686
};
6787

6888
return new Promise((resolve, reject) => {
69-
localHelper(resolve);
89+
localHelper(resolve,reject);
7090
});
7191
}
7292

@@ -94,10 +114,20 @@ function _anonymizeNodeName(nodeName) {
94114

95115
let Rosnodejs = {
96116
/**
97-
* Initializes a ros node for this process. Only one ros node can exist per process
117+
* Initializes a ros node for this process. Only one ros node can exist per process.
98118
* If called a second time with the same nodeName, returns a handle to that node.
99-
* @param nodeName {string} name of the node to initialize
100-
* @param options {object} overrides for this node
119+
* @param {string} nodeName name of the node to initialize
120+
* @param {object} options overrides for this node
121+
* @param {boolean} options.anonymous Set node to be anonymous
122+
* @param {object} options.logging logger options for this node
123+
* @param {function} options.logging.getLoggers the function for setting which loggers
124+
* to be used for this node
125+
* @param {function} options.logging.setLoggerLevel the function for setting the logger
126+
* level
127+
* @param {string} options.rosMasterUri the Master URI to use for this node
128+
* @param {number} options.timeout time in ms to wait for node to be initialized
129+
* before timing out. A negative value will retry forever.
130+
* A value of '0' will try once before stopping. @default -1
101131
* @return {Promise} resolved when connection to master is established
102132
*/
103133
initNode(nodeName, options) {
@@ -113,8 +143,8 @@ let Rosnodejs = {
113143
return Promise.resolve(this.getNodeHandle());
114144
}
115145
// else
116-
throw new Error('Unable to initialize node [' + nodeName + '] - node ['
117-
+ rosNode.getNodeName() + '] already exists');
146+
return Promise.reject( Error('Unable to initialize node [' + nodeName + '] - node ['
147+
+ rosNode.getNodeName() + '] already exists'));
118148
}
119149

120150
let rosMasterUri = process.env.ROS_MASTER_URI;
@@ -129,14 +159,18 @@ let Rosnodejs = {
129159
const nodeOpts = options.node || {};
130160
rosNode = new RosNode(nodeName, rosMasterUri, nodeOpts);
131161

132-
return this._loadOnTheFlyMessages(options)
133-
.then(_checkMasterHelper)
162+
return new Promise((resolve,reject)=>{
163+
this._loadOnTheFlyMessages(options)
164+
.then(()=>{return _checkMasterHelper(100, options.timeout);})
134165
.then(Logging.initializeRosOptions.bind(Logging, this, options.logging))
135-
.then(Time._initializeRosTime.bind(Time, this))
136-
.then(() => { return this.getNodeHandle(); })
166+
.then(Time._initializeRosTime.bind(Time, this, options.notime))
167+
.then(() => { resolve(this.getNodeHandle()); })
137168
.catch((err) => {
138169
log.error('Error during initialization: ' + err);
170+
this.shutdown();
171+
reject(err);
139172
});
173+
});
140174
},
141175

142176
reset() {

src/lib/Time.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ function handleSimTimeMessage(msg) {
1010
const Time = {
1111
useSimTime: false,
1212

13-
_initializeRosTime(rosnodejs) {
13+
_initializeRosTime(rosnodejs, notime) {
14+
//Only for testing purposes!
15+
if (notime) {
16+
return Promise.resolve();
17+
}
1418
const nh = rosnodejs.nh;
1519
return nh.getParam('/use_sim_time')
1620
.then((val) => {

test/Log.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ describe('Logging', () => {
4343
masterStub = xmlrpc.createServer({host: 'localhost', port: MASTER_PORT}, () => {
4444
rosnodejs.initNode('/testNode', {
4545
rosMasterUri: `http://localhost:${MASTER_PORT}`,
46-
logging: {skipRosLogging: true}
46+
logging: {skipRosLogging: true},
47+
notime: true
4748
})
4849
.then(() => {
4950
rosnodejs.log.addStream({
@@ -308,7 +309,7 @@ describe('Logging', () => {
308309
.then(() => {
309310
rosnodejs.reset();
310311
return rosnodejs.initNode('/testNode', {logging: {waitOnRosOut: false, level: 'info'},
311-
rosMasterUri: `http://localhost:${MASTER_PORT}`});
312+
rosMasterUri: `http://localhost:${MASTER_PORT}`, notime: true});
312313
})
313314
.then(() => {
314315
done();

test/onTheFly.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ describe('OnTheFly', function () {
2020
return rosnodejs.initNode('/testNode', {
2121
rosMasterUri: `http://localhost:${MASTER_PORT}`,
2222
onTheFly: true,
23+
notime: true,
2324
logging: {skipRosLogging: true}})
2425
.then(() => {
2526
done();

test/stress.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ describe('ClientShutdown', function() {
174174
console.error('Got unknown method call %s: %j', method, params);
175175
});
176176

177-
return rosnodejs.initNode('/my_node', {rosMasterUri: `http://localhost:${MASTER_PORT}`, logging: {testing: true}});
177+
return rosnodejs.initNode('/my_node', {rosMasterUri: `http://localhost:${MASTER_PORT}`, logging: {testing: true}, notime:true});
178178
});
179179

180180
afterEach(() => {

test/xmlrpcTest.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ describe('Protocol Test', () => {
2525
let masterStub;
2626
const initArgs = {
2727
rosMasterUri: `http://localhost:${MASTER_PORT}`,
28-
logging: {skipRosLogging: true}
28+
logging: {skipRosLogging: true},
29+
notime: true
2930
};
3031
const nodeName = '/testNode';
3132

0 commit comments

Comments
 (0)