Skip to content
This repository was archived by the owner on Apr 22, 2025. It is now read-only.

Commit eccc738

Browse files
committed
FAB-4850 Orderer reconnect on errors
PS 3 Make timeout for orderer waits configurable. PS 4 Strubs are not reused managedchannel maintains single connection no need to warn. PS 5 Factor out timeout setting Change-Id: Ice49db47580723bf983a411f253268a7e00c7991 Signed-off-by: rickr <cr22rc@gmail.com>
1 parent 7c87f20 commit eccc738

File tree

2 files changed

+161
-116
lines changed

2 files changed

+161
-116
lines changed

src/main/java/org/hyperledger/fabric/sdk/Orderer.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,8 @@ Ab.BroadcastResponse sendTransaction(Common.Envelope transaction) throws Excepti
129129
}
130130

131131
try {
132-
Ab.BroadcastResponse resp = localOrdererClient.sendTransaction(transaction);
133132

134-
return resp;
135-
} catch (TransactionException e) { //For any error lets start with a fresh connection.
136-
ordererClient = null;
137-
throw e;
133+
return localOrdererClient.sendTransaction(transaction);
138134
} catch (Throwable t) {
139135
ordererClient = null;
140136
throw t;
@@ -165,12 +161,8 @@ DeliverResponse[] sendDeliver(Common.Envelope transaction) throws TransactionExc
165161
}
166162

167163
try {
168-
DeliverResponse[] response = localOrdererClient.sendDeliver(transaction);
169164

170-
return response;
171-
} catch (TransactionException e) { //For any error lets start with a fresh connection.
172-
ordererClient = null;
173-
throw e;
165+
return localOrdererClient.sendDeliver(transaction);
174166
} catch (Throwable t) {
175167
ordererClient = null;
176168
throw t;

src/main/java/org/hyperledger/fabric/sdk/OrdererClient.java

Lines changed: 159 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,19 @@
3838
*/
3939
class OrdererClient {
4040
private final String channelName;
41-
boolean shutdown = false;
41+
private final ManagedChannelBuilder channelBuilder;
42+
private boolean shutdown = false;
4243
private static final Log logger = LogFactory.getLog(OrdererClient.class);
43-
private ManagedChannel managedChannel;
44+
private ManagedChannel managedChannel = null;
4445
private final String name;
4546
private final String url;
4647

4748
/**
4849
* Construct client for accessing Orderer server using the existing managedChannel.
4950
*/
5051
OrdererClient(Orderer orderer, ManagedChannelBuilder<?> channelBuilder) {
51-
managedChannel = channelBuilder.build();
52+
53+
this.channelBuilder = channelBuilder;
5254
name = orderer.getName();
5355
url = orderer.getUrl();
5456
channelName = orderer.getChannel().getName();
@@ -87,155 +89,206 @@ public void finalize() {
8789
}
8890

8991
Ab.BroadcastResponse sendTransaction(Common.Envelope envelope) throws Exception {
92+
StreamObserver<Common.Envelope> nso = null;
9093

9194
if (shutdown) {
9295
throw new TransactionException("Orderer client is shutdown");
9396
}
9497

95-
final CountDownLatch finishLatch = new CountDownLatch(1);
96-
AtomicBroadcastGrpc.AtomicBroadcastStub broadcast = AtomicBroadcastGrpc.newStub(managedChannel);
97-
AtomicBroadcastGrpc.AtomicBroadcastBlockingStub bsc = AtomicBroadcastGrpc.newBlockingStub(managedChannel);
98-
bsc.withDeadlineAfter(2, TimeUnit.MINUTES);
98+
ManagedChannel lmanagedChannel = managedChannel;
9999

100-
final Ab.BroadcastResponse[] ret = new Ab.BroadcastResponse[1];
101-
final Throwable[] throwable = new Throwable[] {null};
100+
if (lmanagedChannel == null || lmanagedChannel.isTerminated() || lmanagedChannel.isShutdown()) {
102101

103-
StreamObserver<Ab.BroadcastResponse> so = new StreamObserver<Ab.BroadcastResponse>() {
104-
@Override
105-
public void onNext(Ab.BroadcastResponse resp) {
106-
// logger.info("Got Broadcast response: " + resp);
107-
logger.debug("resp status value: " + resp.getStatusValue() + ", resp: " + resp.getStatus());
108-
ret[0] = resp;
109-
finishLatch.countDown();
102+
lmanagedChannel = channelBuilder.build();
103+
managedChannel = lmanagedChannel;
110104

111-
}
105+
}
106+
107+
try {
108+
final CountDownLatch finishLatch = new CountDownLatch(1);
109+
AtomicBroadcastGrpc.AtomicBroadcastStub broadcast = AtomicBroadcastGrpc.newStub(lmanagedChannel);
110+
111+
final Ab.BroadcastResponse[] ret = new Ab.BroadcastResponse[1];
112+
final Throwable[] throwable = new Throwable[] {null};
113+
114+
StreamObserver<Ab.BroadcastResponse> so = new StreamObserver<Ab.BroadcastResponse>() {
115+
@Override
116+
public void onNext(Ab.BroadcastResponse resp) {
117+
// logger.info("Got Broadcast response: " + resp);
118+
logger.debug("resp status value: " + resp.getStatusValue() + ", resp: " + resp.getStatus());
119+
ret[0] = resp;
120+
finishLatch.countDown();
112121

113-
@Override
114-
public void onError(Throwable t) {
115-
if (!shutdown) {
116-
logger.error(format("Received error on channel %s, orderer %s, url %s, %s",
117-
channelName, name, url, t.getMessage()), t);
118122
}
119-
throwable[0] = t;
120-
finishLatch.countDown();
121-
}
122123

123-
@Override
124-
public void onCompleted() {
125-
logger.warn("onCompleted");
126-
finishLatch.countDown();
127-
}
128-
};
124+
@Override
125+
public void onError(Throwable t) {
126+
if (!shutdown) {
127+
logger.error(format("Received error on channel %s, orderer %s, url %s, %s",
128+
channelName, name, url, t.getMessage()), t);
129+
}
130+
throwable[0] = t;
131+
finishLatch.countDown();
132+
}
129133

130-
StreamObserver<Common.Envelope> nso = broadcast.broadcast(so);
134+
@Override
135+
public void onCompleted() {
136+
finishLatch.countDown();
137+
}
138+
};
131139

132-
nso.onNext(envelope);
133-
//nso.onCompleted();
140+
nso = broadcast.broadcast(so);
141+
142+
nso.onNext(envelope);
143+
144+
try {
145+
if (!finishLatch.await(2, TimeUnit.MINUTES)) {
146+
TransactionException ste = new TransactionException("Send transactions failed. Reason: timeout");
147+
logger.error("sendTransaction error " + ste.getMessage(), ste);
148+
throw ste;
149+
}
150+
151+
if (throwable[0] != null) {
152+
//get full stack trace
153+
TransactionException ste = new TransactionException("Send transactions failed. Reason: " + throwable[0].getMessage(), throwable[0]);
154+
logger.error("sendTransaction error " + ste.getMessage(), ste);
155+
throw ste;
156+
}
157+
logger.debug("Done waiting for reply! Got:" + ret[0]);
158+
159+
} catch (InterruptedException e) {
160+
logger.error(e);
134161

135-
try {
136-
if (!finishLatch.await(2, TimeUnit.MINUTES)) {
137-
TransactionException ste = new TransactionException("Send transactions failed. Reason: timeout");
138-
logger.error("sendTransaction error " + ste.getMessage(), ste);
139-
throw ste;
140-
}
141-
if (throwable[0] != null) {
142-
//get full stack trace
143-
TransactionException ste = new TransactionException("Send transactions failed. Reason: " + throwable[0].getMessage(), throwable[0]);
144-
logger.error("sendTransaction error " + ste.getMessage(), ste);
145-
throw ste;
146162
}
147-
logger.debug("Done waiting for reply! Got:" + ret[0]);
148163

149-
} catch (InterruptedException e) {
150-
logger.error(e);
164+
return ret[0];
165+
} catch (Throwable t) {
166+
managedChannel = null;
167+
throw t;
151168

152-
}
169+
} finally {
170+
171+
if (null != nso) {
172+
173+
try {
174+
nso.onCompleted();
175+
} catch (Exception e) { //Best effort only report on debug
176+
logger.debug(format("Exception completing sendTransaction with channel %s, name %s, url %s %s",
177+
channelName, name, url, e.getMessage()), e);
178+
}
179+
}
153180

154-
return ret[0];
181+
}
155182
}
156183

157-
public DeliverResponse[] sendDeliver(Common.Envelope envelope) throws TransactionException {
184+
DeliverResponse[] sendDeliver(Common.Envelope envelope) throws TransactionException {
158185

159186
if (shutdown) {
160187
throw new TransactionException("Orderer client is shutdown");
161188
}
162189

163-
final CountDownLatch finishLatch = new CountDownLatch(1);
164-
AtomicBroadcastGrpc.AtomicBroadcastStub broadcast = AtomicBroadcastGrpc.newStub(managedChannel);
165-
AtomicBroadcastGrpc.AtomicBroadcastBlockingStub bsc = AtomicBroadcastGrpc.newBlockingStub(managedChannel);
166-
bsc.withDeadlineAfter(2, TimeUnit.MINUTES);
190+
StreamObserver<Common.Envelope> nso = null;
167191

168-
// final DeliverResponse[] ret = new DeliverResponse[1];
169-
final List<DeliverResponse> retList = new ArrayList<>();
170-
final List<Throwable> throwableList = new ArrayList<>();
171-
// ret[0] = null;
192+
ManagedChannel lmanagedChannel = managedChannel;
172193

173-
StreamObserver<DeliverResponse> so = new StreamObserver<DeliverResponse>() {
174-
boolean done = false;
194+
if (lmanagedChannel == null || lmanagedChannel.isTerminated() || lmanagedChannel.isShutdown()) {
175195

176-
@Override
177-
public void onNext(DeliverResponse resp) {
196+
lmanagedChannel = channelBuilder.build();
197+
managedChannel = lmanagedChannel;
178198

179-
// logger.info("Got Broadcast response: " + resp);
180-
logger.debug("resp status value: " + resp.getStatusValue() + ", resp: " + resp.getStatus() + ", type case: " + resp.getTypeCase());
199+
}
181200

182-
if (done) {
183-
return;
184-
}
201+
try {
202+
203+
AtomicBroadcastGrpc.AtomicBroadcastStub broadcast = AtomicBroadcastGrpc.newStub(lmanagedChannel);
204+
205+
// final DeliverResponse[] ret = new DeliverResponse[1];
206+
final List<DeliverResponse> retList = new ArrayList<>();
207+
final List<Throwable> throwableList = new ArrayList<>();
208+
final CountDownLatch finishLatch = new CountDownLatch(1);
209+
210+
StreamObserver<DeliverResponse> so = new StreamObserver<DeliverResponse>() {
211+
boolean done = false;
185212

186-
if (resp.getTypeCase() == STATUS) {
187-
done = true;
188-
retList.add(0, resp);
213+
@Override
214+
public void onNext(DeliverResponse resp) {
189215

216+
// logger.info("Got Broadcast response: " + resp);
217+
logger.debug("resp status value: " + resp.getStatusValue() + ", resp: " + resp.getStatus() + ", type case: " + resp.getTypeCase());
218+
219+
if (done) {
220+
return;
221+
}
222+
223+
if (resp.getTypeCase() == STATUS) {
224+
done = true;
225+
retList.add(0, resp);
226+
227+
finishLatch.countDown();
228+
229+
} else {
230+
retList.add(resp);
231+
}
232+
233+
}
234+
235+
@Override
236+
public void onError(Throwable t) {
237+
if (!shutdown) {
238+
logger.error(format("Received error on channel %s, orderer %s, url %s, %s",
239+
channelName, name, url, t.getMessage()), t);
240+
}
241+
throwableList.add(t);
190242
finishLatch.countDown();
243+
}
191244

192-
} else {
193-
retList.add(resp);
245+
@Override
246+
public void onCompleted() {
247+
logger.warn("onCompleted");
248+
finishLatch.countDown();
194249
}
250+
};
195251

196-
}
252+
nso = broadcast.deliver(so);
253+
nso.onNext(envelope);
254+
//nso.onCompleted();
197255

198-
@Override
199-
public void onError(Throwable t) {
200-
if (!shutdown) {
201-
logger.error(format("Received error on channel %s, orderer %s, url %s, %s",
202-
channelName, name, url, t.getMessage()), t);
256+
try {
257+
if (!finishLatch.await(2, TimeUnit.MINUTES)) {
258+
TransactionException ex = new TransactionException("sendDeliver time exceeded for orderer");
259+
logger.error(ex.getMessage(), ex);
260+
throw ex;
203261
}
204-
throwableList.add(t);
205-
finishLatch.countDown();
262+
logger.trace("Done waiting for reply!");
263+
264+
} catch (InterruptedException e) {
265+
logger.error(e);
206266
}
207267

208-
@Override
209-
public void onCompleted() {
210-
logger.warn("onCompleted");
211-
finishLatch.countDown();
268+
if (!throwableList.isEmpty()) {
269+
Throwable throwable = throwableList.get(0);
270+
TransactionException e = new TransactionException(throwable.getMessage(), throwable);
271+
logger.error(e.getMessage(), e);
272+
throw e;
212273
}
213-
};
214274

215-
StreamObserver<Common.Envelope> nso = broadcast.deliver(so);
216-
nso.onNext(envelope);
217-
//nso.onCompleted();
275+
return retList.toArray(new DeliverResponse[retList.size()]);
276+
} catch (Throwable t) {
277+
managedChannel = null;
278+
throw t;
218279

219-
try {
220-
if (!finishLatch.await(2, TimeUnit.MINUTES)) {
221-
TransactionException ex = new TransactionException("sendDeliver time exceeded for orderer");
222-
logger.error(ex.getMessage(), ex);
223-
throw ex;
224-
}
225-
logger.trace("Done waiting for reply!");
280+
} finally {
281+
if (null != nso) {
226282

227-
} catch (InterruptedException e) {
228-
logger.error(e);
229-
}
283+
try {
284+
nso.onCompleted();
285+
} catch (Exception e) { //Best effort only report on debug
286+
logger.debug(format("Exception completing sendDeliver with channel %s, name %s, url %s %s",
287+
channelName, name, url, e.getMessage()), e);
288+
}
230289

231-
if (!throwableList.isEmpty()) {
232-
Throwable throwable = throwableList.get(0);
233-
TransactionException e = new TransactionException(throwable.getMessage(), throwable);
234-
logger.error(e.getMessage(), e);
235-
throw e;
290+
}
236291
}
237-
238-
return retList.toArray(new DeliverResponse[retList.size()]);
239292
}
240293

241294
boolean isChannelActive() {

0 commit comments

Comments
 (0)