exec

package
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 17, 2026 License: AGPL-3.0 Imports: 21 Imported by: 0

README

limit to 1000 events per execution limit each of the events to 256 kiB limit total testing time to 5 minutes limit timeout between consecutive events since the first event is 20 seconds limit to handling one execution events at a time for now

the total memory usage is limited to 256 MiB per execution

for the notifier channels place the information onto disk

we have to somehow simulate the receiving of many events and monitor memory usage

get rid of the handlers channel to avoid writing to closed channel and goroutine circus.

ExecSrvc - code execution service

The current execution transport is Core NATS. See NATS execution transport for subject ownership, result streaming, and test-file retrieval. The SQS notes below are obsolete and have been removed.

A Go package that provides a robust service for executing and testing code submissions in various programming languages.

This service is designed to handle concurrent test execution while maintaining ordered result streaming and proper resource management.

Features

  • Publish code execution requests through Core NATS
  • Execute code in different programming languages with customizable compilation and execution commands
  • Maintain sequential ordering of test results even with concurrent test execution
  • Store completed execution results in the configured file store
  • Stream execution events for real-time progress monitoring
  • Verify execution parameters like memory limits and timeouts

Core Components

  • ExecSrvc: Main service that handles code execution requests and result management
  • ExecResStreamOrganizer: Manages ordered streaming of execution results
  • ExecRepo: Interface for execution result storage

Usage

srvc := execsrvc.NewExecSrvc(
    ctx,
    execRepository,
    natsConnection,
    testfileStore,
)

err := srvc.Enqueue(ctx, execUUID, sourceCode, languageID, tests, params)

// Get execution results
exec, err := srvc.Get(ctx, execUUID)

Configuration

The service uses NATS_URL and FILE_STORAGE_ROOT. The HTTP fallback for test files additionally depends on API_PUBLIC_BASE_URL and TESTFILE_DOWNLOAD_SIGNING_KEY.

TODO / ideas

  • Integrate with submission service using PostgreSQL for scoring storage
  • Implement minimum memory limits per programming language
  • Add support for evaluation without API key (without result persistence)

Documentation

Index

Constants

View Source
const (
	ReceivedSubmissionType  = "received_submission"
	StartedCompilationType  = "started_compilation"
	FinishedCompilationType = "finished_compilation"
	CompilationErrorType    = "compilation_error"
	ReachedTestType         = "reached_test"
	IgnoredTestType         = "ignored_test"
	FinishedTestType        = "finished_test"
	FinishedTestingType     = "finished_testing"
	InternalServerErrorType = "internal_server_error"
)
View Source
const ErrCodeCheckerTooLarge = "checker_too_large"
View Source
const ErrCodeConstraintTooLose = "constraint_too_loose"
View Source
const ErrCodeEvalNotFound = "eval_not_found"
View Source
const ErrCodeInteractorTooLarge = "interactor_too_large"
View Source
const ErrCodeInvalidTestFile = "invalid_test_file"
View Source
const ErrCodeInvalidTesterParams = "invalid_tester_params"
View Source
const ErrCodeMemConstraintTooLose = "mem_constraint_too_loose"
View Source
const ErrCodeTooManyTests = "too_many_tests"
View Source
const NatsSubject = "tester.jobs"

Variables

View Source
var ErrCheckerTooLarge = srvcerror.New(
	ErrCodeCheckerTooLarge,
	"Checker program too large",
).SetHttpStatusCode(http.StatusBadRequest)
View Source
var ErrCpuConstraintTooLose = srvcerror.New(
	ErrCodeConstraintTooLose,
	"CPU time limit too long",
).SetHttpStatusCode(http.StatusBadRequest)
View Source
var ErrEvalNotFound = srvcerror.New(
	ErrCodeEvalNotFound,
	"Evaluation not found",
).SetHttpStatusCode(http.StatusNotFound)
View Source
var ErrInteractorTooLarge = srvcerror.New(
	ErrCodeInteractorTooLarge,
	"Interactor program too large",
).SetHttpStatusCode(http.StatusBadRequest)
View Source
var ErrInvalidTestFile = srvcerror.New(
	ErrCodeInvalidTestFile,
	"Invalid test file",
).SetHttpStatusCode(http.StatusBadRequest)
View Source
var ErrInvalidTesterParams = srvcerror.New(
	ErrCodeInvalidTesterParams,
	"invalid tester parameters",
).SetHttpStatusCode(http.StatusBadRequest)
View Source
var ErrMemConstraintTooLose = srvcerror.New(
	ErrCodeMemConstraintTooLose,
	"Memory limit too large",
).SetHttpStatusCode(http.StatusBadRequest)
View Source
var ErrTooManyTests = srvcerror.New(
	ErrCodeTooManyTests,
	"Too many tests",
).SetHttpStatusCode(http.StatusBadRequest)

Functions

func NewExecSrvc

func NewExecSrvc(ctx context.Context, repo ExecRepo, natsConn *nats.Conn, testfileStore TestFileStore) *execSrvc

Types

type CodeExecutionService

type CodeExecutionService interface {
	Enqueue(ctx context.Context, uuid uuid.UUID, srcCode string, prLangId string, tests []TestFile, params TestingParams) srvcerror.E
	Listen(ctx context.Context, uuid uuid.UUID) (<-chan Event, srvcerror.E)
	Get(ctx context.Context, execUuid uuid.UUID) (Execution, srvcerror.E)
}

type CodeWithLang

type CodeWithLang struct {
	SrcCode string // user submitted solution source code
	LangId  string // short compiler, interpreter id
}

user submitted solution

type CompilationError

type CompilationError struct {
	ErrorMsg *string `json:"error_msg"`
}

func (CompilationError) MarshalJSON

func (s CompilationError) MarshalJSON() ([]byte, error)

func (CompilationError) Type

func (s CompilationError) Type() string

type Event

type Event interface {
	Type() string
	MarshalJSON() ([]byte, error)
}

type ExecRepo

type ExecRepo interface {
	Save(ctx context.Context, exec *Execution) error
	Get(ctx context.Context, id uuid.UUID) (*Execution, error)
}

ExecRepo interface for execution storage

type ExecRequest

type ExecRequest struct {
	UUID  uuid.UUID
	Code  string
	Lang  PrLang
	Tests []TestFile

	CpuMs  int `json:"cpu_ms"`  // max user-mode CPU time in milliseconds
	MemKiB int `json:"mem_kib"` // max resident set size in kibibytes

	// optional testlib.h checker program. If not provided,
	// only output of the user's solution is returned from tester
	// and is not viable for grading. "run program" use case.
	Checker *string `json:"checker"`

	// optional testlib.h interactor program.
	Interactor *string `json:"interactor"`
}

func (ExecRequest) IsValid

func (e ExecRequest) IsValid() error

func (ExecRequest) MapToTesterApiType

func (e ExecRequest) MapToTesterApiType() *testerapi.ExecReq

type ExecResStreamOrganizer

type ExecResStreamOrganizer struct {
	// contains filtered or unexported fields
}

ExecResStreamOrganizer processes and orders a stream of testing events to ensure:

  • Sequential ordering: Events are emitted only after their dependencies are satisfied
  • Deduplication: Events with identical keys are processed only once
  • Completeness: All required events must be received before testing completion

The organizer supports concurrent test execution while maintaining sequential event emission. For example, if test #2 finishes before test #1, the organizer will buffer test #2's results until test #1's results are processed.

func (*ExecResStreamOrganizer) Add

func (o *ExecResStreamOrganizer) Add(
	event Event,
) ([]Event, error)

Add processes an incoming event and returns any events that are now ready for emission. Events are considered ready when all their dependencies have been satisfied and emitted. For example:

  • Test results require their "test reached" event
  • Tests require compilation success if compiled

Handles deduplication and sequential ordering. Returns error if event type is unknown.

func (*ExecResStreamOrganizer) HasFinished

func (o *ExecResStreamOrganizer) HasFinished() bool

HasFinished indicates whether evaluation has completed and no more events will be processed. This occurs when:

  • Internal server error encountered
  • All tests complete successfully
  • Compilation fails

type ExecStage

type ExecStage string
const (
	StageWaiting       ExecStage = "waiting"
	StageCompiling     ExecStage = "compiling"
	StageTesting       ExecStage = "testing"
	StageFinished      ExecStage = "finished"
	StageCompileError  ExecStage = "compile_error"
	StageInternalError ExecStage = "internal_error"
)

type Execution

type Execution struct {
	UUID      uuid.UUID     `json:"uuid"`
	Stage     ExecStage     `json:"stage"`
	TestRes   []TestRes     `json:"test_res"`
	PrLang    PrLang        `json:"pr_lang"`
	Params    TestingParams `json:"params"`
	ErrorMsg  *string       `json:"error_msg"`
	SysInfo   *string       `json:"sys_info"` // testing hardware info
	CreatedAt time.Time     `json:"created_at"`
	SubmComp  *RunData      `json:"subm_comp"` // submitted code compilation runtime data

}

func (*Execution) SimilarTo

func (e *Execution) SimilarTo(other Execution) error

Does not compare UUID, SysInfo, CreatedAt Ensures that execution time deviations are within reasonable deviations

type FileEvalRepo

type FileEvalRepo struct {
	// contains filtered or unexported fields
}

func NewFileExecRepo

func NewFileExecRepo(ctx context.Context, store *filestore.Store) *FileEvalRepo

func (*FileEvalRepo) Get

func (r *FileEvalRepo) Get(ctx context.Context, evalUuid uuid.UUID) (*Execution, error)

func (*FileEvalRepo) Save

func (r *FileEvalRepo) Save(ctx context.Context, eval *Execution) error

type FinishedCompiling

type FinishedCompiling struct {
	RuntimeData *RunData `json:"runtime_data"`
}

func (FinishedCompiling) MarshalJSON

func (s FinishedCompiling) MarshalJSON() ([]byte, error)

func (FinishedCompiling) Type

func (s FinishedCompiling) Type() string

type FinishedTest

type FinishedTest struct {
	TestID  int      `json:"test_id"`
	Subm    *RunData `json:"submission"`
	Checker *RunData `json:"checker"`
}

func (FinishedTest) MarshalJSON

func (s FinishedTest) MarshalJSON() ([]byte, error)

func (FinishedTest) Type

func (s FinishedTest) Type() string

type FinishedTesting

type FinishedTesting struct{}

func (FinishedTesting) MarshalJSON

func (s FinishedTesting) MarshalJSON() ([]byte, error)

func (FinishedTesting) Type

func (s FinishedTesting) Type() string

type IgnoredTest

type IgnoredTest struct {
	TestId int `json:"test_id"`
}

func (IgnoredTest) MarshalJSON

func (s IgnoredTest) MarshalJSON() ([]byte, error)

func (IgnoredTest) Type

func (s IgnoredTest) Type() string

type InMemExecRepo

type InMemExecRepo struct {
	// contains filtered or unexported fields
}

func NewInMemExecRepo

func NewInMemExecRepo() *InMemExecRepo

func (*InMemExecRepo) Get

func (i *InMemExecRepo) Get(ctx context.Context, id uuid.UUID) (*Execution, error)

Get implements ExecRepo.

func (*InMemExecRepo) Save

func (i *InMemExecRepo) Save(ctx context.Context, exec *Execution) error

Save implements ExecRepo.

type InternalServerError

type InternalServerError struct {
	ErrorMsg *string `json:"error_msg"`
}

func (InternalServerError) MarshalJSON

func (s InternalServerError) MarshalJSON() ([]byte, error)

func (InternalServerError) Type

func (s InternalServerError) Type() string

type PrLang

type PrLang struct {
	ShortId   string  `json:"short_id"`   // short lang/compiler/interpreter id
	Display   string  `json:"display"`    // user-friendly programming lang name
	CodeFname string  `json:"code_fname"` // source code filename for mv in to box
	CompCmd   *string `json:"comp_cmd"`   // compile command
	CompFname *string `json:"comp_fname"` // exe fname after comp for mv out of box
	ExecCmd   string  `json:"exec_cmd"`   // execution command
}

type ReachedTest

type ReachedTest struct {
	TestId int     `json:"test_id"`
	In     *string `json:"in"`
	Ans    *string `json:"ans"`
}

func (ReachedTest) MarshalJSON

func (s ReachedTest) MarshalJSON() ([]byte, error)

func (ReachedTest) Type

func (s ReachedTest) Type() string

type ReceivedSubmission

type ReceivedSubmission struct {
	SysInfo   string    `json:"sys_info"`
	StartedAt time.Time `json:"started_at"`
}

func (ReceivedSubmission) MarshalJSON

func (s ReceivedSubmission) MarshalJSON() ([]byte, error)

func (ReceivedSubmission) Type

func (s ReceivedSubmission) Type() string

type RunData

type RunData struct {
	StdIn       string  `json:"in"`            // standard input
	StdOut      string  `json:"out"`           // standard output
	StdErr      string  `json:"err"`           // standard error
	CpuMs       int64   `json:"cpu_ms"`        // cpu user-mode time in milliseconds
	WallMs      int64   `json:"wall_ms"`       // wall clock time in milliseconds
	MemKiB      int64   `json:"mem_kib"`       // memory usage (resident set size) in kibibytes
	ExitCode    int64   `json:"exit"`          // exit code
	CtxSwV      int64   `json:"ctx_sw_v"`      // voluntary context switches, e.g. waiting for I/O
	CtxSwF      int64   `json:"ctx_sw_f"`      // involuntary context switches, e.g. waiting for CPU
	Signal      *int64  `json:"signal"`        // exit signal if any
	IsOomKilled bool    `json:"is_oom_killed"` // whether the process was killed due to memory exhaustion
	IsolStatus  *string `json:"isol_status"`   // isolate sandbox execution environment status
	IsolMsg     *string `json:"isol_msg"`      // isolate sandbox execution environment message
}

Runtime Data

func (*RunData) SimilarTo

func (r *RunData) SimilarTo(other RunData) error

type StartedCompiling

type StartedCompiling struct{}

func (StartedCompiling) MarshalJSON

func (s StartedCompiling) MarshalJSON() ([]byte, error)

func (StartedCompiling) Type

func (s StartedCompiling) Type() string

type TestFile

type TestFile struct {
	InSha256   *string // SHA256 hash of input for caching
	InDownlUrl *string // URL to download input
	InContent  *string // input content as alternative to URL

	AnsSha256   *string // SHA256 hash of answer for caching
	AnsDownlUrl *string // URL to download answer
	AnsContent  *string // answer content as alternative to URL
}

input and expected output

func (*TestFile) IsValid

func (t *TestFile) IsValid() error

type TestFileStore

type TestFileStore interface {
	Open(key string) (io.ReadCloser, error)
}

type TestRes

type TestRes struct {
	ID       int     `json:"id"`
	Input    *string `json:"inp"` // trimmed test input file preview
	Answer   *string `json:"ans"` // trimmed test answer file preview
	Reached  bool    `json:"rch"`
	Ignored  bool    `json:"ign"` // when score group has another failed test
	Finished bool    `json:"fin"`

	Subm    *RunData `json:"subm_rd"` // user submitted solution
	Checker *RunData `json:"tlib_rd"` // testlib checker
}

func (*TestRes) SimilarTo

func (t *TestRes) SimilarTo(other TestRes) error

type TestingParams

type TestingParams struct {
	CpuMs  int `json:"cpu_ms"`  // maximum user-mode CPU time in milliseconds
	MemKiB int `json:"mem_kib"` // maximum resident set size in kibibytes

	// optional testlib.h checker program. If not provided,
	// only output of the user's solution is returned from tester
	// and is not viable for grading. "run program" use case.
	Checker *string `json:"checker"`

	// optional testlib.h interactor program.
	Interactor *string `json:"interactor"`
}

Tester machine submitted solution runtime constraints

func (*TestingParams) IsValid

func (p *TestingParams) IsValid() error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL