aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/pkg/exec.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-01-11 17:46:04 +0900
committerOphestra <cat@gensokyo.uk>2026-01-11 17:46:04 +0900
commit7ccc2fc5ece9c6236c02585ef4048fdc2b4a5b51 (patch)
tree3e63ab8aeb380b256cc36c42c5ca4c1cac8de728 /internal/pkg/exec.go
parent63e137856e47bb9cb472fc58ee6ea0b2e6c666b8 (diff)
internal/pkg: exec with specific timeout
This change also updates the documentation of NewExec. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/pkg/exec.go')
-rw-r--r--internal/pkg/exec.go35
1 files changed, 29 insertions, 6 deletions
diff --git a/internal/pkg/exec.go b/internal/pkg/exec.go
index db0cf9f0..2ded00e9 100644
--- a/internal/pkg/exec.go
+++ b/internal/pkg/exec.go
@@ -42,6 +42,13 @@ func MustPath(pathname string, writable bool, a ...Artifact) ExecPath {
return ExecPath{check.MustAbs(pathname), a, writable}
}
+const (
+ // ExecTimeoutDefault replaces out of range [NewExec] timeout values.
+ ExecTimeoutDefault = 15 * time.Minute
+ // ExecTimeoutMax is the arbitrary upper bound of [NewExec] timeout.
+ ExecTimeoutMax = 48 * time.Hour
+)
+
// An execArtifact is an [Artifact] that produces output by running a program
// part of another [Artifact] in a [container] to produce its output.
//
@@ -59,6 +66,11 @@ type execArtifact struct {
path *check.Absolute
// Passed through to [container.Params].
args []string
+
+ // Duration the initial process is allowed to run. The zero value is
+ // equivalent to execTimeoutDefault. This value is never encoded in Params
+ // because it cannot affect outcome.
+ timeout time.Duration
}
// execNetArtifact is like execArtifact but implements [KnownChecksum] and has
@@ -88,10 +100,9 @@ func (a *execNetArtifact) Cure(f *FContext) error {
return a.cure(f, true)
}
-// NewExec returns a new [Artifact] bounded by ctx, it cures all [Artifact]
-// in paths at the specified maximum concurrent cures limit. Specified paths are
-// bind mounted read-only in the specified order in the resulting container.
-// A private instance of /proc and /dev is made available to the container.
+// NewExec returns a new [Artifact] that executes the program path in a
+// container with specified paths bind mounted read-only in order. A private
+// instance of /proc and /dev is made available to the container.
//
// The working and temporary directories are both created and mounted writable
// on [AbsWork] and [fhs.AbsTmp] respectively. If one or more paths target
@@ -103,8 +114,14 @@ func (a *execNetArtifact) Cure(f *FContext) error {
//
// If checksum is non-nil, the resulting [Artifact] implements [KnownChecksum]
// and its container runs in the host net namespace.
+//
+// The container is allowed to run for the specified duration before the initial
+// process and all processes originating from it is terminated. A zero or
+// negative timeout value is equivalent tp [ExecTimeoutDefault], a timeout value
+// greater than [ExecTimeoutMax] is equivalent to [ExecTimeoutMax].
func NewExec(
checksum *Checksum,
+ timeout time.Duration,
dir *check.Absolute,
env []string,
@@ -113,7 +130,13 @@ func NewExec(
paths ...ExecPath,
) Artifact {
- a := execArtifact{paths, dir, env, path, args}
+ if timeout <= 0 {
+ timeout = ExecTimeoutDefault
+ }
+ if timeout > ExecTimeoutMax {
+ timeout = ExecTimeoutMax
+ }
+ a := execArtifact{paths, dir, env, path, args, timeout}
if checksum == nil {
return &a
}
@@ -197,7 +220,7 @@ func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) {
artifactCount += len(p.A)
}
- ctx, cancel := context.WithCancel(f.Unwrap())
+ ctx, cancel := context.WithTimeout(f.Unwrap(), a.timeout)
defer cancel()
z := container.New(ctx, f.GetMessage())