Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ jobs:
defaults:
run:
working-directory: runner
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- name: Set up Go
Expand Down
42 changes: 33 additions & 9 deletions runner/internal/executor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"os/exec"
osuser "os/user"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
Expand All @@ -27,6 +28,12 @@ import (
"github.com/prometheus/procfs"
)

type ConnectionTracker interface {
GetNoConnectionsSecs() int64
Track(ticker <-chan time.Time)
Stop()
}

type RunExecutor struct {
tempDir string
homeDir string
Expand All @@ -51,9 +58,16 @@ type RunExecutor struct {
timestamp *MonotonicTimestamp

killDelay time.Duration
connectionTracker *connections.ConnectionTracker
connectionTracker ConnectionTracker
}

// stubConnectionTracker is a no-op implementation for when procfs is not available (only required for tests on darwin)
type stubConnectionTracker struct{}

func (s *stubConnectionTracker) GetNoConnectionsSecs() int64 { return 0 }
func (s *stubConnectionTracker) Track(ticker <-chan time.Time) {}
func (s *stubConnectionTracker) Stop() {}

func NewRunExecutor(tempDir string, homeDir string, workingDir string, sshPort int) (*RunExecutor, error) {
mu := &sync.RWMutex{}
timestamp := NewMonotonicTimestamp()
Expand All @@ -65,15 +79,25 @@ func NewRunExecutor(tempDir string, homeDir string, workingDir string, sshPort i
if err != nil {
return nil, fmt.Errorf("failed to parse current user uid: %w", err)
}
proc, err := procfs.NewDefaultFS()
if err != nil {
return nil, fmt.Errorf("failed to initialize procfs: %w", err)

// Try to initialize procfs, but don't fail if it's not available (e.g., on macOS)
var connectionTracker ConnectionTracker

if runtime.GOOS == "linux" {
proc, err := procfs.NewDefaultFS()
if err != nil {
return nil, fmt.Errorf("failed to initialize procfs: %w", err)
}
connectionTracker = connections.NewConnectionTracker(connections.ConnectionTrackerConfig{
Port: uint64(sshPort),
MinConnDuration: 10 * time.Second, // shorter connections are likely from dstack-server
Procfs: proc,
})
} else {
// Use stub connection tracker (only required for tests on darwin)
connectionTracker = &stubConnectionTracker{}
}
connectionTracker := connections.NewConnectionTracker(connections.ConnectionTrackerConfig{
Port: uint64(sshPort),
MinConnDuration: 10 * time.Second, // shorter connections are likely from dstack-server
Procfs: proc,
})

return &RunExecutor{
tempDir: tempDir,
homeDir: homeDir,
Expand Down
7 changes: 7 additions & 0 deletions runner/internal/metrics/metrics_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package metrics

import (
"runtime"
"testing"

"github.com/dstackai/dstack/runner/internal/schemas"
"github.com/stretchr/testify/assert"
)

func TestGetAMDGPUMetrics_OK(t *testing.T) {
if runtime.GOOS == "darwin" {
t.Skip("Skipping on macOS")
}
collector, err := NewMetricsCollector()
assert.NoError(t, err)

Expand Down Expand Up @@ -39,6 +43,9 @@ func TestGetAMDGPUMetrics_OK(t *testing.T) {
}

func TestGetAMDGPUMetrics_ErrorGPUUtilNA(t *testing.T) {
if runtime.GOOS == "darwin" {
t.Skip("Skipping on macOS")
}
collector, err := NewMetricsCollector()
assert.NoError(t, err)
metrics, err := collector.getAMDGPUMetrics("gpu,gfx,gfx_clock,vram_used,vram_total\n0,N/A,N/A,283,196300\n")
Expand Down
Loading