github.com/eth-easl/loader@v0.0.0-20230908084258-8a37e1d94279/pkg/driver/grpc_client.go (about) 1 /* 2 * MIT License 3 * 4 * Copyright (c) 2023 EASL and the vHive community 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in all 14 * copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 25 package driver 26 27 import ( 28 "context" 29 "strings" 30 "time" 31 32 "github.com/eth-easl/loader/pkg/common" 33 "github.com/eth-easl/loader/pkg/config" 34 "github.com/eth-easl/loader/pkg/workload/proto" 35 36 log "github.com/sirupsen/logrus" 37 "google.golang.org/grpc" 38 "google.golang.org/grpc/credentials/insecure" 39 40 "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" 41 42 mc "github.com/eth-easl/loader/pkg/metric" 43 ) 44 45 func Invoke(function *common.Function, runtimeSpec *common.RuntimeSpecification, cfg *config.LoaderConfiguration) (bool, *mc.ExecutionRecord) { 46 log.Tracef("(Invoke)\t %s: %d[ms], %d[MiB]", function.Name, runtimeSpec.Runtime, runtimeSpec.Memory) 47 48 record := &mc.ExecutionRecord{ 49 ExecutionRecordBase: mc.ExecutionRecordBase{ 50 RequestedDuration: uint32(runtimeSpec.Runtime * 1e3), 51 }, 52 } 53 54 //////////////////////////////////// 55 // INVOKE FUNCTION 56 //////////////////////////////////// 57 start := time.Now() 58 record.StartTime = start.UnixMicro() 59 60 dialContext, cancelDialing := context.WithTimeout(context.Background(), time.Duration(cfg.GRPCConnectionTimeoutSeconds)*time.Second) 61 defer cancelDialing() 62 63 var dialOptions []grpc.DialOption 64 dialOptions = append(dialOptions, grpc.WithTransportCredentials(insecure.NewCredentials())) 65 dialOptions = append(dialOptions, grpc.WithBlock()) 66 if cfg.EnableZipkinTracing { 67 // NOTE: if enabled it will exclude Istio span from the Zipkin trace 68 dialOptions = append(dialOptions, grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor())) 69 } 70 71 conn, err := grpc.DialContext(dialContext, function.Endpoint, dialOptions...) 72 defer gRPCConnectionClose(conn) 73 if err != nil { 74 log.Debugf("Failed to establish a gRPC connection - %v\n", err) 75 76 record.ResponseTime = time.Since(start).Microseconds() 77 record.ConnectionTimeout = true 78 79 return false, record 80 } 81 82 grpcClient := proto.NewExecutorClient(conn) 83 84 executionCxt, cancelExecution := context.WithTimeout(context.Background(), time.Duration(cfg.GRPCFunctionTimeoutSeconds)*time.Second) 85 defer cancelExecution() 86 87 response, err := grpcClient.Execute(executionCxt, &proto.FaasRequest{ 88 Message: "nothing", 89 RuntimeInMilliSec: uint32(runtimeSpec.Runtime), 90 MemoryInMebiBytes: uint32(runtimeSpec.Memory), 91 }) 92 93 if err != nil { 94 log.Debugf("gRPC timeout exceeded for function %s - %s", function.Name, err) 95 96 record.ResponseTime = time.Since(start).Microseconds() 97 record.FunctionTimeout = true 98 99 return false, record 100 } 101 102 record.Instance = extractInstanceName(response.GetMessage()) 103 record.ResponseTime = time.Since(start).Microseconds() 104 record.ActualDuration = response.DurationInMicroSec 105 106 if strings.HasPrefix(response.GetMessage(), "FAILURE - mem_alloc") { 107 record.MemoryAllocationTimeout = true 108 } else { 109 record.ActualMemoryUsage = common.Kib2Mib(response.MemoryUsageInKb) 110 } 111 112 log.Tracef("(Replied)\t %s: %s, %.2f[ms], %d[MiB]", function.Name, response.Message, 113 float64(response.DurationInMicroSec)/1e3, common.Kib2Mib(response.MemoryUsageInKb)) 114 log.Tracef("(E2E Latency) %s: %.2f[ms]\n", function.Name, float64(record.ResponseTime)/1e3) 115 116 return true, record 117 } 118 119 func extractInstanceName(data string) string { 120 indexOfHyphen := strings.LastIndex(data, common.FunctionNamePrefix) 121 if indexOfHyphen == -1 { 122 return data 123 } 124 125 return data[indexOfHyphen:] 126 } 127 128 func gRPCConnectionClose(conn *grpc.ClientConn) { 129 if conn == nil { 130 return 131 } 132 133 if err := conn.Close(); err != nil { 134 log.Warnf("Error while closing gRPC connection - %s\n", err) 135 } 136 }