routines: Add system for routine initialization
This commit is contained in:
		
							parent
							
								
									57e6f63124
								
							
						
					
					
						commit
						816c3e1fc3
					
				| @ -26,6 +26,16 @@ type Routine interface { | |||||||
| 	Run (context.Context) error | 	Run (context.Context) error | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // InitRoutine is a routine that has to be initialized before it can be run. | ||||||
|  | type InitRoutine interface { | ||||||
|  | 	Routine | ||||||
|  | 
 | ||||||
|  | 	// Init is an initialization function that is called before any routines | ||||||
|  | 	// are run, including this one. Routines must not depend on eachother in | ||||||
|  | 	// this function. | ||||||
|  | 	Init (context.Context) error | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // Manager is a system capable of managing multiple routines, and restarting | // Manager is a system capable of managing multiple routines, and restarting | ||||||
| // them if they fail. | // them if they fail. | ||||||
| type Manager struct { | type Manager struct { | ||||||
| @ -41,9 +51,13 @@ type Manager struct { | |||||||
| 	// Logger, if non-nil, is where log messages will be written to. If it | 	// Logger, if non-nil, is where log messages will be written to. If it | ||||||
| 	// is nil, messages will be written to the standard logger. To disable | 	// is nil, messages will be written to the standard logger. To disable | ||||||
| 	// logging altogether, this can be set to io.Discard. | 	// logging altogether, this can be set to io.Discard. | ||||||
| 	Logger io.Writer | 	Logger     io.Writer | ||||||
|  | 	loggerLock sync.Mutex | ||||||
| 
 | 
 | ||||||
| 	ctx context.Context | 	ctx context.Context | ||||||
|  | 
 | ||||||
|  | 	failed     map[Routine] struct { } | ||||||
|  | 	failedLock sync.Mutex | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Run spawns all routines in the Routines slice. If a routine exits with an | // Run spawns all routines in the Routines slice. If a routine exits with an | ||||||
| @ -52,14 +66,24 @@ type Manager struct { | |||||||
| func (this *Manager) Run (ctx context.Context) error { | func (this *Manager) Run (ctx context.Context) error { | ||||||
| 	ctx, done := context.WithCancel(ctx) | 	ctx, done := context.WithCancel(ctx) | ||||||
| 	this.ctx = ctx | 	this.ctx = ctx | ||||||
|  | 	this.failed = make(map[Routine] struct { }) | ||||||
| 
 | 
 | ||||||
| 	var waitGroup sync.WaitGroup | 	var waitGroup sync.WaitGroup | ||||||
| 	for _, routine := range this.Routines { | 	for _, routine := range this.Routines { | ||||||
| 		if routine != nil { | 		if routine != nil { | ||||||
|  | 			waitGroup.Add(1) | ||||||
|  | 			go this.initRoutine(routine, &waitGroup) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	waitGroup.Wait() | ||||||
|  | 	 | ||||||
|  | 	for _, routine := range this.Routines { | ||||||
|  | 		if _, failed := this.failed[routine]; !failed { | ||||||
| 			waitGroup.Add(1) | 			waitGroup.Add(1) | ||||||
| 			go this.runRoutine(routine, &waitGroup) | 			go this.runRoutine(routine, &waitGroup) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	this.failed = nil | ||||||
| 	waitGroup.Wait() | 	waitGroup.Wait() | ||||||
| 	 | 	 | ||||||
| 	done() | 	done() | ||||||
| @ -73,6 +97,8 @@ func (this *Manager) Append (routines ...Routine) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (this *Manager) log (message ...any) { | func (this *Manager) log (message ...any) { | ||||||
|  | 	this.loggerLock.Lock() | ||||||
|  | 	defer this.loggerLock.Unlock() | ||||||
| 	if this.Logger == nil { | 	if this.Logger == nil { | ||||||
| 		log.Println(message...) | 		log.Println(message...) | ||||||
| 	} else { | 	} else { | ||||||
| @ -80,6 +106,20 @@ func (this *Manager) log (message ...any) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (this *Manager) initRoutine (routine Routine, group *sync.WaitGroup) { | ||||||
|  | 	defer group.Done() | ||||||
|  | 
 | ||||||
|  | 	if initRoutine, ok := routine.(InitRoutine); ok { | ||||||
|  | 		err := initRoutine.Init(this.ctx) | ||||||
|  | 		if err != nil { | ||||||
|  | 			this.log("XXX routine failed to initialize:", err) | ||||||
|  | 			this.failedLock.Lock() | ||||||
|  | 			defer this.failedLock.Unlock() | ||||||
|  | 			this.failed[routine] = struct { } { } | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (this *Manager) runRoutine (routine Routine, group *sync.WaitGroup) { | func (this *Manager) runRoutine (routine Routine, group *sync.WaitGroup) { | ||||||
| 	defer group.Done() | 	defer group.Done() | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user