github.com/onflow/flow-go@v0.33.17/engine/access/apiproxy/access_api_proxy.go (about) 1 package apiproxy 2 3 import ( 4 "context" 5 6 "google.golang.org/grpc/status" 7 8 "github.com/rs/zerolog" 9 10 "github.com/onflow/flow/protobuf/go/flow/access" 11 12 "github.com/onflow/flow-go/engine/access/rpc/connection" 13 "github.com/onflow/flow-go/engine/common/grpc/forwarder" 14 "github.com/onflow/flow-go/engine/protocol" 15 "github.com/onflow/flow-go/model/flow" 16 "github.com/onflow/flow-go/module/metrics" 17 ) 18 19 // FlowAccessAPIRouter is a structure that represents the routing proxy algorithm. 20 // It splits requests between a local and a remote API service. 21 type FlowAccessAPIRouter struct { 22 Logger zerolog.Logger 23 Metrics *metrics.ObserverCollector 24 Upstream *FlowAccessAPIForwarder 25 Observer *protocol.Handler 26 } 27 28 func (h *FlowAccessAPIRouter) log(handler, rpc string, err error) { 29 code := status.Code(err) 30 h.Metrics.RecordRPC(handler, rpc, code) 31 32 logger := h.Logger.With(). 33 Str("handler", handler). 34 Str("grpc_method", rpc). 35 Str("grpc_code", code.String()). 36 Logger() 37 38 if err != nil { 39 logger.Error().Err(err).Msg("request failed") 40 return 41 } 42 43 logger.Info().Msg("request succeeded") 44 } 45 46 // Ping pings the service. It is special in the sense that it responds successful, 47 // only if all underlying services are ready. 48 func (h *FlowAccessAPIRouter) Ping(context context.Context, req *access.PingRequest) (*access.PingResponse, error) { 49 h.log("observer", "Ping", nil) 50 return &access.PingResponse{}, nil 51 } 52 53 func (h *FlowAccessAPIRouter) GetNodeVersionInfo(ctx context.Context, request *access.GetNodeVersionInfoRequest) (*access.GetNodeVersionInfoResponse, error) { 54 res, err := h.Observer.GetNodeVersionInfo(ctx, request) 55 h.log("observer", "GetNodeVersionInfo", err) 56 return res, err 57 } 58 59 func (h *FlowAccessAPIRouter) GetLatestBlockHeader(context context.Context, req *access.GetLatestBlockHeaderRequest) (*access.BlockHeaderResponse, error) { 60 res, err := h.Observer.GetLatestBlockHeader(context, req) 61 h.log("observer", "GetLatestBlockHeader", err) 62 return res, err 63 } 64 65 func (h *FlowAccessAPIRouter) GetBlockHeaderByID(context context.Context, req *access.GetBlockHeaderByIDRequest) (*access.BlockHeaderResponse, error) { 66 res, err := h.Observer.GetBlockHeaderByID(context, req) 67 h.log("observer", "GetBlockHeaderByID", err) 68 return res, err 69 } 70 71 func (h *FlowAccessAPIRouter) GetBlockHeaderByHeight(context context.Context, req *access.GetBlockHeaderByHeightRequest) (*access.BlockHeaderResponse, error) { 72 res, err := h.Observer.GetBlockHeaderByHeight(context, req) 73 h.log("observer", "GetBlockHeaderByHeight", err) 74 return res, err 75 } 76 77 func (h *FlowAccessAPIRouter) GetLatestBlock(context context.Context, req *access.GetLatestBlockRequest) (*access.BlockResponse, error) { 78 res, err := h.Observer.GetLatestBlock(context, req) 79 h.log("observer", "GetLatestBlock", err) 80 return res, err 81 } 82 83 func (h *FlowAccessAPIRouter) GetBlockByID(context context.Context, req *access.GetBlockByIDRequest) (*access.BlockResponse, error) { 84 res, err := h.Observer.GetBlockByID(context, req) 85 h.log("observer", "GetBlockByID", err) 86 return res, err 87 } 88 89 func (h *FlowAccessAPIRouter) GetBlockByHeight(context context.Context, req *access.GetBlockByHeightRequest) (*access.BlockResponse, error) { 90 res, err := h.Observer.GetBlockByHeight(context, req) 91 h.log("observer", "GetBlockByHeight", err) 92 return res, err 93 } 94 95 func (h *FlowAccessAPIRouter) GetCollectionByID(context context.Context, req *access.GetCollectionByIDRequest) (*access.CollectionResponse, error) { 96 res, err := h.Upstream.GetCollectionByID(context, req) 97 h.log("upstream", "GetCollectionByID", err) 98 return res, err 99 } 100 101 func (h *FlowAccessAPIRouter) SendTransaction(context context.Context, req *access.SendTransactionRequest) (*access.SendTransactionResponse, error) { 102 res, err := h.Upstream.SendTransaction(context, req) 103 h.log("upstream", "SendTransaction", err) 104 return res, err 105 } 106 107 func (h *FlowAccessAPIRouter) GetTransaction(context context.Context, req *access.GetTransactionRequest) (*access.TransactionResponse, error) { 108 res, err := h.Upstream.GetTransaction(context, req) 109 h.log("upstream", "GetTransaction", err) 110 return res, err 111 } 112 113 func (h *FlowAccessAPIRouter) GetTransactionResult(context context.Context, req *access.GetTransactionRequest) (*access.TransactionResultResponse, error) { 114 res, err := h.Upstream.GetTransactionResult(context, req) 115 h.log("upstream", "GetTransactionResult", err) 116 return res, err 117 } 118 119 func (h *FlowAccessAPIRouter) GetTransactionResultsByBlockID(context context.Context, req *access.GetTransactionsByBlockIDRequest) (*access.TransactionResultsResponse, error) { 120 res, err := h.Upstream.GetTransactionResultsByBlockID(context, req) 121 h.log("upstream", "GetTransactionResultsByBlockID", err) 122 return res, err 123 } 124 125 func (h *FlowAccessAPIRouter) GetTransactionsByBlockID(context context.Context, req *access.GetTransactionsByBlockIDRequest) (*access.TransactionsResponse, error) { 126 res, err := h.Upstream.GetTransactionsByBlockID(context, req) 127 h.log("upstream", "GetTransactionsByBlockID", err) 128 return res, err 129 } 130 131 func (h *FlowAccessAPIRouter) GetTransactionResultByIndex(context context.Context, req *access.GetTransactionByIndexRequest) (*access.TransactionResultResponse, error) { 132 res, err := h.Upstream.GetTransactionResultByIndex(context, req) 133 h.log("upstream", "GetTransactionResultByIndex", err) 134 return res, err 135 } 136 137 func (h *FlowAccessAPIRouter) GetSystemTransaction(context context.Context, req *access.GetSystemTransactionRequest) (*access.TransactionResponse, error) { 138 res, err := h.Upstream.GetSystemTransaction(context, req) 139 h.log("upstream", "GetSystemTransaction", err) 140 return res, err 141 } 142 143 func (h *FlowAccessAPIRouter) GetSystemTransactionResult(context context.Context, req *access.GetSystemTransactionResultRequest) (*access.TransactionResultResponse, error) { 144 res, err := h.Upstream.GetSystemTransactionResult(context, req) 145 h.log("upstream", "GetSystemTransactionResult", err) 146 return res, err 147 } 148 149 func (h *FlowAccessAPIRouter) GetAccount(context context.Context, req *access.GetAccountRequest) (*access.GetAccountResponse, error) { 150 res, err := h.Upstream.GetAccount(context, req) 151 h.log("upstream", "GetAccount", err) 152 return res, err 153 } 154 155 func (h *FlowAccessAPIRouter) GetAccountAtLatestBlock(context context.Context, req *access.GetAccountAtLatestBlockRequest) (*access.AccountResponse, error) { 156 res, err := h.Upstream.GetAccountAtLatestBlock(context, req) 157 h.log("upstream", "GetAccountAtLatestBlock", err) 158 return res, err 159 } 160 161 func (h *FlowAccessAPIRouter) GetAccountAtBlockHeight(context context.Context, req *access.GetAccountAtBlockHeightRequest) (*access.AccountResponse, error) { 162 res, err := h.Upstream.GetAccountAtBlockHeight(context, req) 163 h.log("upstream", "GetAccountAtBlockHeight", err) 164 return res, err 165 } 166 167 func (h *FlowAccessAPIRouter) ExecuteScriptAtLatestBlock(context context.Context, req *access.ExecuteScriptAtLatestBlockRequest) (*access.ExecuteScriptResponse, error) { 168 res, err := h.Upstream.ExecuteScriptAtLatestBlock(context, req) 169 h.log("upstream", "ExecuteScriptAtLatestBlock", err) 170 return res, err 171 } 172 173 func (h *FlowAccessAPIRouter) ExecuteScriptAtBlockID(context context.Context, req *access.ExecuteScriptAtBlockIDRequest) (*access.ExecuteScriptResponse, error) { 174 res, err := h.Upstream.ExecuteScriptAtBlockID(context, req) 175 h.log("upstream", "ExecuteScriptAtBlockID", err) 176 return res, err 177 } 178 179 func (h *FlowAccessAPIRouter) ExecuteScriptAtBlockHeight(context context.Context, req *access.ExecuteScriptAtBlockHeightRequest) (*access.ExecuteScriptResponse, error) { 180 res, err := h.Upstream.ExecuteScriptAtBlockHeight(context, req) 181 h.log("upstream", "ExecuteScriptAtBlockHeight", err) 182 return res, err 183 } 184 185 func (h *FlowAccessAPIRouter) GetEventsForHeightRange(context context.Context, req *access.GetEventsForHeightRangeRequest) (*access.EventsResponse, error) { 186 res, err := h.Upstream.GetEventsForHeightRange(context, req) 187 h.log("upstream", "GetEventsForHeightRange", err) 188 return res, err 189 } 190 191 func (h *FlowAccessAPIRouter) GetEventsForBlockIDs(context context.Context, req *access.GetEventsForBlockIDsRequest) (*access.EventsResponse, error) { 192 res, err := h.Upstream.GetEventsForBlockIDs(context, req) 193 h.log("upstream", "GetEventsForBlockIDs", err) 194 return res, err 195 } 196 197 func (h *FlowAccessAPIRouter) GetNetworkParameters(context context.Context, req *access.GetNetworkParametersRequest) (*access.GetNetworkParametersResponse, error) { 198 res, err := h.Observer.GetNetworkParameters(context, req) 199 h.log("observer", "GetNetworkParameters", err) 200 return res, err 201 } 202 203 func (h *FlowAccessAPIRouter) GetLatestProtocolStateSnapshot(context context.Context, req *access.GetLatestProtocolStateSnapshotRequest) (*access.ProtocolStateSnapshotResponse, error) { 204 res, err := h.Observer.GetLatestProtocolStateSnapshot(context, req) 205 h.log("observer", "GetLatestProtocolStateSnapshot", err) 206 return res, err 207 } 208 209 func (h *FlowAccessAPIRouter) GetProtocolStateSnapshotByBlockID(context context.Context, req *access.GetProtocolStateSnapshotByBlockIDRequest) (*access.ProtocolStateSnapshotResponse, error) { 210 res, err := h.Observer.GetProtocolStateSnapshotByBlockID(context, req) 211 h.log("observer", "GetProtocolStateSnapshotByBlockID", err) 212 return res, err 213 } 214 215 func (h *FlowAccessAPIRouter) GetProtocolStateSnapshotByHeight(context context.Context, req *access.GetProtocolStateSnapshotByHeightRequest) (*access.ProtocolStateSnapshotResponse, error) { 216 res, err := h.Observer.GetProtocolStateSnapshotByHeight(context, req) 217 h.log("observer", "GetProtocolStateSnapshotByHeight", err) 218 return res, err 219 } 220 221 func (h *FlowAccessAPIRouter) GetExecutionResultForBlockID(context context.Context, req *access.GetExecutionResultForBlockIDRequest) (*access.ExecutionResultForBlockIDResponse, error) { 222 res, err := h.Upstream.GetExecutionResultForBlockID(context, req) 223 h.log("upstream", "GetExecutionResultForBlockID", err) 224 return res, err 225 } 226 227 func (h *FlowAccessAPIRouter) GetExecutionResultByID(context context.Context, req *access.GetExecutionResultByIDRequest) (*access.ExecutionResultByIDResponse, error) { 228 res, err := h.Upstream.GetExecutionResultByID(context, req) 229 h.log("upstream", "GetExecutionResultByID", err) 230 return res, err 231 } 232 233 // FlowAccessAPIForwarder forwards all requests to a set of upstream access nodes or observers 234 type FlowAccessAPIForwarder struct { 235 *forwarder.Forwarder 236 } 237 238 func NewFlowAccessAPIForwarder(identities flow.IdentityList, connectionFactory connection.ConnectionFactory) (*FlowAccessAPIForwarder, error) { 239 forwarder, err := forwarder.NewForwarder(identities, connectionFactory) 240 if err != nil { 241 return nil, err 242 } 243 244 return &FlowAccessAPIForwarder{ 245 Forwarder: forwarder, 246 }, nil 247 } 248 249 // Ping pings the service. It is special in the sense that it responds successful, 250 // only if all underlying services are ready. 251 func (h *FlowAccessAPIForwarder) Ping(context context.Context, req *access.PingRequest) (*access.PingResponse, error) { 252 // This is a passthrough request 253 upstream, closer, err := h.FaultTolerantClient() 254 if err != nil { 255 return nil, err 256 } 257 defer closer.Close() 258 return upstream.Ping(context, req) 259 } 260 261 func (h *FlowAccessAPIForwarder) GetNodeVersionInfo(context context.Context, req *access.GetNodeVersionInfoRequest) (*access.GetNodeVersionInfoResponse, error) { 262 // This is a passthrough request 263 upstream, closer, err := h.FaultTolerantClient() 264 if err != nil { 265 return nil, err 266 } 267 defer closer.Close() 268 return upstream.GetNodeVersionInfo(context, req) 269 } 270 271 func (h *FlowAccessAPIForwarder) GetLatestBlockHeader(context context.Context, req *access.GetLatestBlockHeaderRequest) (*access.BlockHeaderResponse, error) { 272 // This is a passthrough request 273 upstream, closer, err := h.FaultTolerantClient() 274 if err != nil { 275 return nil, err 276 } 277 defer closer.Close() 278 return upstream.GetLatestBlockHeader(context, req) 279 } 280 281 func (h *FlowAccessAPIForwarder) GetBlockHeaderByID(context context.Context, req *access.GetBlockHeaderByIDRequest) (*access.BlockHeaderResponse, error) { 282 // This is a passthrough request 283 upstream, closer, err := h.FaultTolerantClient() 284 if err != nil { 285 return nil, err 286 } 287 defer closer.Close() 288 return upstream.GetBlockHeaderByID(context, req) 289 } 290 291 func (h *FlowAccessAPIForwarder) GetBlockHeaderByHeight(context context.Context, req *access.GetBlockHeaderByHeightRequest) (*access.BlockHeaderResponse, error) { 292 // This is a passthrough request 293 upstream, closer, err := h.FaultTolerantClient() 294 if err != nil { 295 return nil, err 296 } 297 defer closer.Close() 298 return upstream.GetBlockHeaderByHeight(context, req) 299 } 300 301 func (h *FlowAccessAPIForwarder) GetLatestBlock(context context.Context, req *access.GetLatestBlockRequest) (*access.BlockResponse, error) { 302 // This is a passthrough request 303 upstream, closer, err := h.FaultTolerantClient() 304 if err != nil { 305 return nil, err 306 } 307 defer closer.Close() 308 return upstream.GetLatestBlock(context, req) 309 } 310 311 func (h *FlowAccessAPIForwarder) GetBlockByID(context context.Context, req *access.GetBlockByIDRequest) (*access.BlockResponse, error) { 312 // This is a passthrough request 313 upstream, closer, err := h.FaultTolerantClient() 314 if err != nil { 315 return nil, err 316 } 317 defer closer.Close() 318 return upstream.GetBlockByID(context, req) 319 } 320 321 func (h *FlowAccessAPIForwarder) GetBlockByHeight(context context.Context, req *access.GetBlockByHeightRequest) (*access.BlockResponse, error) { 322 // This is a passthrough request 323 upstream, closer, err := h.FaultTolerantClient() 324 if err != nil { 325 return nil, err 326 } 327 defer closer.Close() 328 return upstream.GetBlockByHeight(context, req) 329 } 330 331 func (h *FlowAccessAPIForwarder) GetCollectionByID(context context.Context, req *access.GetCollectionByIDRequest) (*access.CollectionResponse, error) { 332 // This is a passthrough request 333 upstream, closer, err := h.FaultTolerantClient() 334 if err != nil { 335 return nil, err 336 } 337 defer closer.Close() 338 return upstream.GetCollectionByID(context, req) 339 } 340 341 func (h *FlowAccessAPIForwarder) SendTransaction(context context.Context, req *access.SendTransactionRequest) (*access.SendTransactionResponse, error) { 342 // This is a passthrough request 343 upstream, closer, err := h.FaultTolerantClient() 344 if err != nil { 345 return nil, err 346 } 347 defer closer.Close() 348 return upstream.SendTransaction(context, req) 349 } 350 351 func (h *FlowAccessAPIForwarder) GetTransaction(context context.Context, req *access.GetTransactionRequest) (*access.TransactionResponse, error) { 352 // This is a passthrough request 353 upstream, closer, err := h.FaultTolerantClient() 354 if err != nil { 355 return nil, err 356 } 357 defer closer.Close() 358 return upstream.GetTransaction(context, req) 359 } 360 361 func (h *FlowAccessAPIForwarder) GetTransactionResult(context context.Context, req *access.GetTransactionRequest) (*access.TransactionResultResponse, error) { 362 // This is a passthrough request 363 upstream, closer, err := h.FaultTolerantClient() 364 if err != nil { 365 return nil, err 366 } 367 defer closer.Close() 368 return upstream.GetTransactionResult(context, req) 369 } 370 371 func (h *FlowAccessAPIForwarder) GetSystemTransaction(context context.Context, req *access.GetSystemTransactionRequest) (*access.TransactionResponse, error) { 372 // This is a passthrough request 373 upstream, closer, err := h.FaultTolerantClient() 374 if err != nil { 375 return nil, err 376 } 377 defer closer.Close() 378 return upstream.GetSystemTransaction(context, req) 379 } 380 381 func (h *FlowAccessAPIForwarder) GetSystemTransactionResult(context context.Context, req *access.GetSystemTransactionResultRequest) (*access.TransactionResultResponse, error) { 382 // This is a passthrough request 383 upstream, closer, err := h.FaultTolerantClient() 384 if err != nil { 385 return nil, err 386 } 387 defer closer.Close() 388 return upstream.GetSystemTransactionResult(context, req) 389 } 390 391 func (h *FlowAccessAPIForwarder) GetTransactionResultByIndex(context context.Context, req *access.GetTransactionByIndexRequest) (*access.TransactionResultResponse, error) { 392 // This is a passthrough request 393 upstream, closer, err := h.FaultTolerantClient() 394 if err != nil { 395 return nil, err 396 } 397 defer closer.Close() 398 return upstream.GetTransactionResultByIndex(context, req) 399 } 400 401 func (h *FlowAccessAPIForwarder) GetTransactionResultsByBlockID(context context.Context, req *access.GetTransactionsByBlockIDRequest) (*access.TransactionResultsResponse, error) { 402 // This is a passthrough request 403 upstream, closer, err := h.FaultTolerantClient() 404 if err != nil { 405 return nil, err 406 } 407 defer closer.Close() 408 return upstream.GetTransactionResultsByBlockID(context, req) 409 } 410 411 func (h *FlowAccessAPIForwarder) GetTransactionsByBlockID(context context.Context, req *access.GetTransactionsByBlockIDRequest) (*access.TransactionsResponse, error) { 412 upstream, closer, err := h.FaultTolerantClient() 413 if err != nil { 414 return nil, err 415 } 416 defer closer.Close() 417 return upstream.GetTransactionsByBlockID(context, req) 418 } 419 420 func (h *FlowAccessAPIForwarder) GetAccount(context context.Context, req *access.GetAccountRequest) (*access.GetAccountResponse, error) { 421 // This is a passthrough request 422 upstream, closer, err := h.FaultTolerantClient() 423 if err != nil { 424 return nil, err 425 } 426 defer closer.Close() 427 return upstream.GetAccount(context, req) 428 } 429 430 func (h *FlowAccessAPIForwarder) GetAccountAtLatestBlock(context context.Context, req *access.GetAccountAtLatestBlockRequest) (*access.AccountResponse, error) { 431 // This is a passthrough request 432 upstream, closer, err := h.FaultTolerantClient() 433 if err != nil { 434 return nil, err 435 } 436 defer closer.Close() 437 return upstream.GetAccountAtLatestBlock(context, req) 438 } 439 440 func (h *FlowAccessAPIForwarder) GetAccountAtBlockHeight(context context.Context, req *access.GetAccountAtBlockHeightRequest) (*access.AccountResponse, error) { 441 // This is a passthrough request 442 upstream, closer, err := h.FaultTolerantClient() 443 if err != nil { 444 return nil, err 445 } 446 defer closer.Close() 447 return upstream.GetAccountAtBlockHeight(context, req) 448 } 449 450 func (h *FlowAccessAPIForwarder) ExecuteScriptAtLatestBlock(context context.Context, req *access.ExecuteScriptAtLatestBlockRequest) (*access.ExecuteScriptResponse, error) { 451 // This is a passthrough request 452 upstream, closer, err := h.FaultTolerantClient() 453 if err != nil { 454 return nil, err 455 } 456 defer closer.Close() 457 return upstream.ExecuteScriptAtLatestBlock(context, req) 458 } 459 460 func (h *FlowAccessAPIForwarder) ExecuteScriptAtBlockID(context context.Context, req *access.ExecuteScriptAtBlockIDRequest) (*access.ExecuteScriptResponse, error) { 461 // This is a passthrough request 462 upstream, closer, err := h.FaultTolerantClient() 463 if err != nil { 464 return nil, err 465 } 466 defer closer.Close() 467 return upstream.ExecuteScriptAtBlockID(context, req) 468 } 469 470 func (h *FlowAccessAPIForwarder) ExecuteScriptAtBlockHeight(context context.Context, req *access.ExecuteScriptAtBlockHeightRequest) (*access.ExecuteScriptResponse, error) { 471 // This is a passthrough request 472 upstream, closer, err := h.FaultTolerantClient() 473 if err != nil { 474 return nil, err 475 } 476 defer closer.Close() 477 return upstream.ExecuteScriptAtBlockHeight(context, req) 478 } 479 480 func (h *FlowAccessAPIForwarder) GetEventsForHeightRange(context context.Context, req *access.GetEventsForHeightRangeRequest) (*access.EventsResponse, error) { 481 // This is a passthrough request 482 upstream, closer, err := h.FaultTolerantClient() 483 if err != nil { 484 return nil, err 485 } 486 defer closer.Close() 487 return upstream.GetEventsForHeightRange(context, req) 488 } 489 490 func (h *FlowAccessAPIForwarder) GetEventsForBlockIDs(context context.Context, req *access.GetEventsForBlockIDsRequest) (*access.EventsResponse, error) { 491 // This is a passthrough request 492 upstream, closer, err := h.FaultTolerantClient() 493 if err != nil { 494 return nil, err 495 } 496 defer closer.Close() 497 return upstream.GetEventsForBlockIDs(context, req) 498 } 499 500 func (h *FlowAccessAPIForwarder) GetNetworkParameters(context context.Context, req *access.GetNetworkParametersRequest) (*access.GetNetworkParametersResponse, error) { 501 // This is a passthrough request 502 upstream, closer, err := h.FaultTolerantClient() 503 if err != nil { 504 return nil, err 505 } 506 defer closer.Close() 507 return upstream.GetNetworkParameters(context, req) 508 } 509 510 func (h *FlowAccessAPIForwarder) GetLatestProtocolStateSnapshot(context context.Context, req *access.GetLatestProtocolStateSnapshotRequest) (*access.ProtocolStateSnapshotResponse, error) { 511 // This is a passthrough request 512 upstream, closer, err := h.FaultTolerantClient() 513 if err != nil { 514 return nil, err 515 } 516 defer closer.Close() 517 return upstream.GetLatestProtocolStateSnapshot(context, req) 518 } 519 520 func (h *FlowAccessAPIForwarder) GetExecutionResultForBlockID(context context.Context, req *access.GetExecutionResultForBlockIDRequest) (*access.ExecutionResultForBlockIDResponse, error) { 521 // This is a passthrough request 522 upstream, closer, err := h.FaultTolerantClient() 523 if err != nil { 524 return nil, err 525 } 526 defer closer.Close() 527 return upstream.GetExecutionResultForBlockID(context, req) 528 } 529 530 func (h *FlowAccessAPIForwarder) GetExecutionResultByID(context context.Context, req *access.GetExecutionResultByIDRequest) (*access.ExecutionResultByIDResponse, error) { 531 // This is a passthrough request 532 upstream, closer, err := h.FaultTolerantClient() 533 if err != nil { 534 return nil, err 535 } 536 defer closer.Close() 537 return upstream.GetExecutionResultByID(context, req) 538 }