func (s *executionServer) Execute(
	req *remoteexecution.ExecuteRequest, execServer remoteexecution.Execution_ExecuteServer) error {
	log.Debugf("Received Execute request: %s", req)
	if !s.IsInitialized() {
		return status.Error(codes.Internal, "Server not initialized")
	}
	var err error = nil
	defer func() {
		if err == nil {
			s.stat.Counter(stats.BzExecSuccessCounter).Inc(1)
		} else {
			s.stat.Counter(stats.BzExecFailureCounter).Inc(1)
		}
	}()
	defer s.stat.Latency(stats.BzExecLatency_ms).Time().Stop()
	job, err := execReqToScoot(req)
	if err != nil {
		log.Errorf("Failed to convert request to Scoot JobDefinition: %s", err)
		return status.Error(codes.InvalidArgument, fmt.Sprintf("Error converting request to internal definition: %s", err))
	}
	err = domain.ValidateJob(job)
	if err != nil {
		log.Errorf("Scoot Job generated from request invalid: %s", err)
		return status.Error(codes.Internal, fmt.Sprintf("Internal job definition invalid: %s", err))
	}
	id, err := s.scheduler.ScheduleJob(job)
	if err != nil {
		log.Errorf("Failed to schedule Scoot job: %s", err)
		return status.Error(codes.Internal, fmt.Sprintf("Failed to schedule Scoot job: %s", err))
	}
	log.WithFields(
		log.Fields{
			"jobID": id,
		}).Info("Scheduled execute request as Scoot job")
	eom := &remoteexecution.ExecuteOperationMetadata{
		Stage:        remoteexecution.ExecuteOperationMetadata_QUEUED,
		ActionDigest: req.GetActionDigest(),
	}
	eomAsPBAny, err := marshalAny(eom)
	if err != nil {
		return status.Error(codes.Internal, err.Error())
	}
	op := &longrunning.Operation{
		Name:     id,
		Metadata: eomAsPBAny,
		Done:     false,
	}
	err = execServer.Send(op)
	if err != nil {
		return status.Error(codes.Internal, err.Error())
	}
	log.Debug("ExecuteRequest completed successfully")
	return nil
}
Execution APIs
Takes an ExecuteRequest and forms an ExecuteResponse that is returned as part of a
google LongRunning Operation message via a stream.
By convention, we will not reuse this stream and the client should
continue to use GetOperation polling to determine execution state.
package execution
import (
	"fmt"
	"net"
	"github.com/golang/protobuf/ptypes/empty"
	log "github.com/sirupsen/logrus"
	"golang.org/x/net/context"
	"google.golang.org/genproto/googleapis/longrunning"
	google_rpc_code "google.golang.org/genproto/googleapis/rpc/code"
	google_rpc_status "google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"github.com/twitter/scoot/bazel"
	"github.com/twitter/scoot/bazel/execution/bazelapi"
	remoteexecution "github.com/twitter/scoot/bazel/remoteexecution"
	loghelpers "github.com/twitter/scoot/common/log/helpers"
	"github.com/twitter/scoot/common/stats"
	"github.com/twitter/scoot/saga"
	"github.com/twitter/scoot/scheduler/api/thrift"
	"github.com/twitter/scoot/scheduler/domain"
	"github.com/twitter/scoot/scheduler/server"
)
type executionServer struct {
	listener  net.Listener
	sagaCoord saga.SagaCoordinator
	server    *grpc.Server
	scheduler server.Scheduler
	stat      stats.StatsReceiver
}
func MakeExecutionServer(gc *bazel.GRPCConfig, s server.Scheduler, stat stats.StatsReceiver) *executionServer {
	if gc == nil {
		return nil
	}
	l, err := gc.NewListener()
	if err != nil {
		panic(err)
	}
	gs := gc.NewGRPCServer()
	g := executionServer{
		listener:  l,
		sagaCoord: s.GetSagaCoord(),
		server:    gs,
		scheduler: s,
		stat:      stat,
	}
	remoteexecution.RegisterExecutionServer(g.server, &g)
	longrunning.RegisterOperationsServer(g.server, &g)
	return &g
}
func (s *executionServer) IsInitialized() bool {
	if s == nil {
		return false
	} else if s.scheduler == nil {
		return false
	}
	return true
}
func (s *executionServer) Serve() error {
	log.Infof("Serving GRPC Execution API on: %s", s.listener.Addr())
	return s.server.Serve(s.listener)
}