or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

command-line-interface.mdenvironment-configuration.mdexport-system.mdindex.mdoutput-formatting.mdprocess-management.md

process-management.mddocs/

0

# Process Management

1

2

Core functionality for managing and orchestrating multiple concurrent processes with lifecycle management, output handling, and signal forwarding. The process management system enables running multiple services simultaneously with proper coordination and cleanup.

3

4

## Capabilities

5

6

### Manager Class

7

8

The Manager class orchestrates multiple processes, handles signals, and manages process lifecycle events. It provides a high-level interface for running multiple processes concurrently with proper event handling and cleanup.

9

10

```python { .api }

11

class Manager:

12

"""

13

Manager is responsible for running multiple external processes in parallel

14

managing the events that result (starting, stopping, printing).

15

"""

16

17

def __init__(self, printer=None):

18

"""

19

Initialize manager with optional printer.

20

21

Parameters:

22

- printer: Printer instance for output formatting (defaults to stdout printer)

23

"""

24

25

def add_process(self, name, cmd, quiet=False, env=None, cwd=None):

26

"""

27

Add a process to this manager instance. The process will not be started

28

until loop() is called.

29

30

Parameters:

31

- name: str, unique process name

32

- cmd: str, command to execute

33

- quiet: bool, whether to suppress process output

34

- env: dict, environment variables for the process

35

- cwd: str, working directory for the process

36

37

Returns:

38

Process: The created process object

39

"""

40

41

def loop(self):

42

"""

43

Start all the added processes and multiplex their output onto the bound

44

printer. If one process terminates, all others will be terminated.

45

This method blocks until all processes have terminated.

46

"""

47

48

def terminate(self):

49

"""

50

Terminate all processes managed by this ProcessManager.

51

"""

52

53

def kill(self):

54

"""

55

Kill all processes managed by this ProcessManager forcefully.

56

"""

57

58

# Properties

59

returncode: Optional[int] # Return code after loop() finishes

60

```

61

62

### Process Class

63

64

Wrapper around subprocess with event forwarding and output handling. Provides a clean interface for individual process management with lifecycle events.

65

66

```python { .api }

67

class Process:

68

"""

69

A utility wrapper around subprocess.Popen that stores attributes needed

70

by Honcho and supports forwarding process lifecycle events and output to a queue.

71

"""

72

73

def __init__(self, cmd, name=None, colour=None, quiet=False, env=None, cwd=None):

74

"""

75

Initialize a process wrapper.

76

77

Parameters:

78

- cmd: str, command to execute

79

- name: str, process name for identification

80

- colour: str, ANSI color code for output

81

- quiet: bool, whether to suppress output

82

- env: dict, environment variables

83

- cwd: str, working directory

84

"""

85

86

def run(self, events=None, ignore_signals=False):

87

"""

88

Run the process and forward events to the queue.

89

90

Parameters:

91

- events: multiprocessing.Queue, event queue for forwarding messages

92

- ignore_signals: bool, whether to ignore SIGINT/SIGTERM

93

"""

94

95

# Properties

96

cmd: str

97

colour: Optional[str]

98

quiet: bool

99

name: Optional[str]

100

env: Dict[str, str]

101

cwd: Optional[str]

102

```

103

104

### Enhanced Subprocess

105

106

Custom Popen subclass with platform-specific optimizations and proper signal handling for process groups.

107

108

```python { .api }

109

class Popen(subprocess.Popen):

110

"""

111

Enhanced subprocess.Popen with platform-specific optimizations.

112

"""

113

114

def __init__(self, cmd, **kwargs):

115

"""

116

Initialize enhanced Popen with default options for Honcho.

117

118

Parameters:

119

- cmd: str, command to execute

120

- **kwargs: additional subprocess options

121

"""

122

```

123

124

### Process Manager Utilities

125

126

Cross-platform process management utilities for terminating and killing process groups.

127

128

```python { .api }

129

class ProcessManager:

130

"""

131

Cross-platform process management utilities.

132

"""

133

134

def terminate(self, pid):

135

"""

136

Terminate process group by PID.

137

138

Parameters:

139

- pid: int, process ID to terminate

140

"""

141

142

def kill(self, pid):

143

"""

144

Kill process group by PID forcefully.

145

146

Parameters:

147

- pid: int, process ID to kill

148

"""

149

```

150

151

## Usage Examples

152

153

### Basic Process Management

154

155

```python

156

import sys

157

from honcho.manager import Manager

158

from honcho.printer import Printer

159

160

# Create manager with custom printer settings

161

manager = Manager(Printer(sys.stdout, colour=True, prefix=True))

162

163

# Add multiple processes

164

manager.add_process('web', 'python app.py', env={'PORT': '5000'})

165

manager.add_process('worker', 'python worker.py', quiet=True)

166

manager.add_process('scheduler', 'python scheduler.py', cwd='/app/scheduler')

167

168

# Start all processes and wait for completion

169

manager.loop()

170

171

# Exit with appropriate return code

172

sys.exit(manager.returncode)

173

```

174

175

### Custom Process Wrapper

176

177

```python

178

from honcho.process import Process

179

import multiprocessing

180

181

# Create event queue for process communication

182

events = multiprocessing.Queue()

183

184

# Create and run individual process

185

process = Process(

186

cmd='python long_running_task.py',

187

name='task',

188

colour='32', # Green

189

env={'DEBUG': '1'}

190

)

191

192

# Run process in background thread or multiprocessing

193

import multiprocessing

194

p = multiprocessing.Process(target=process.run, args=(events, False))

195

p.start()

196

197

# Handle events from queue

198

while True:

199

try:

200

msg = events.get(timeout=1.0)

201

print(f"Event: {msg.type}, Data: {msg.data}")

202

if msg.type == 'stop':

203

break

204

except queue.Empty:

205

continue

206

207

p.join()

208

```

209

210

### Signal Handling

211

212

```python

213

import signal

214

from honcho.manager import Manager

215

216

manager = Manager()

217

manager.add_process('app', 'python app.py')

218

219

# The manager automatically handles SIGINT and SIGTERM

220

# to gracefully terminate all child processes

221

222

try:

223

manager.loop()

224

except KeyboardInterrupt:

225

print("Received interrupt, shutting down...")

226

finally:

227

# Manager automatically cleans up processes

228

sys.exit(manager.returncode or 0)

229

```

230

231

## Constants

232

233

```python { .api }

234

KILL_WAIT = 5 # Seconds to wait before forceful kill

235

SIGNALS = {

236

signal.SIGINT: {'name': 'SIGINT', 'rc': 130},

237

signal.SIGTERM: {'name': 'SIGTERM', 'rc': 143},

238

}

239

SYSTEM_PRINTER_NAME = 'system' # Name for system messages

240

ON_WINDOWS = 'win32' in str(sys.platform).lower() # Platform detection

241

```