Skip to content

Commit d66fdc9

Browse files
authored
Handle peer KEEPALIVE messages in chaincode message handler. (#513)
The Node.js shim exited when the peer sent KEEPALIVE (type 18) on idle connections, which breaks long-running chaincode such as CCAAS. Echo KEEPALIVE back to the peer and align behaviour with the Go chaincode shim. Signed-off-by: Jakub Dzikowski <jakub.t.dzikowski@gmail.com>
1 parent 845e93f commit d66fdc9

2 files changed

Lines changed: 42 additions & 0 deletions

File tree

libraries/fabric-shim/lib/handler.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const MSG_TYPE = {
3535
INIT: peer.ChaincodeMessage.Type.INIT,
3636
TRANSACTION: peer.ChaincodeMessage.Type.TRANSACTION,
3737
COMPLETED: peer.ChaincodeMessage.Type.COMPLETED,
38+
KEEPALIVE: peer.ChaincodeMessage.Type.KEEPALIVE,
3839
};
3940

4041
/*
@@ -295,6 +296,12 @@ class ChaincodeMessageHandler {
295296
stream.on('data', (msgpb) => {
296297
const msg = mapFromChaincodeMessage(msgpb);
297298
logger.debug(util.format('Received chat message from peer: %s, state: %s, type: %s', msg.txid, state, msg.type));
299+
300+
if (msg.type === MSG_TYPE.KEEPALIVE) {
301+
stream.write(msgpb);
302+
return;
303+
}
304+
298305
if (state === STATES.Ready) {
299306
const type = msg.type;
300307

libraries/fabric-shim/test/unit/handler.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,41 @@ describe('Handler', () => {
783783
expect(handleTransactionSpy.firstCall.args).to.deep.equal([mapFromChaincodeMessage(readyMsg)]);
784784
});
785785

786+
it ('should echo KEEPALIVE when in state ready and MSG_TYPE equals KEEPALIVE', () => {
787+
const processStub = sinon.stub(process, 'exit');
788+
789+
eventReg.data(registeredMsg);
790+
eventReg.data(establishedMsg);
791+
792+
const keepaliveMsg = mapToChaincodeMessage({
793+
type: MSG_TYPE.KEEPALIVE
794+
});
795+
796+
eventReg.data(keepaliveMsg);
797+
798+
expect(mockStream.write.calledTwice).to.be.true;
799+
expect(mockStream.write.secondCall.args).to.deep.equal([keepaliveMsg]);
800+
expect(mockNewErrorMsg.notCalled).to.be.true;
801+
expect(handleMsgResponseSpy.notCalled).to.be.true;
802+
expect(handleInitSpy.notCalled).to.be.true;
803+
expect(handleTransactionSpy.notCalled).to.be.true;
804+
expect(processStub.notCalled).to.be.true;
805+
806+
processStub.restore();
807+
});
808+
809+
it ('should echo KEEPALIVE when in state created and MSG_TYPE equals KEEPALIVE', () => {
810+
const keepaliveMsg = mapToChaincodeMessage({
811+
type: MSG_TYPE.KEEPALIVE
812+
});
813+
814+
eventReg.data(keepaliveMsg);
815+
816+
expect(mockStream.write.calledTwice).to.be.true;
817+
expect(mockStream.write.secondCall.args).to.deep.equal([keepaliveMsg]);
818+
expect(mockNewErrorMsg.notCalled).to.be.true;
819+
});
820+
786821
it ('should end the process with value 1', () => {
787822
const processStub = sinon.stub(process, 'exit');
788823

0 commit comments

Comments
 (0)