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  }