Repository: docker/compose
File: pkg/compose/watch.go (Go)

Code before:

func (s *composeService) watchEvents(ctx context.Context, project *types.Project, options api.WatchOptions, watcher watch.Notify, syncer sync.Syncer, rules []watchRule) error {
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	batchEvents := watch.BatchDebounceEvents(ctx, s.clock, watcher.Events())

	for {
		select {
		case <-ctx.Done():
			options.LogTo.Log(api.WatchLogger, "Watch disabled (context canceled)")
			// Ensure watcher is closed to release resources
			_ = watcher.Close()
			return nil
		case err, open := <-watcher.Errors():
			if err != nil {
				options.LogTo.Err(api.WatchLogger, "Watch disabled with errors: "+err.Error())
			}
			if open {
				continue
			}
			_ = watcher.Close()
			return err
		case batch, ok := <-batchEvents:
			if !ok {
				options.LogTo.Log(api.WatchLogger, "Watch event channel closed")
				_ = watcher.Close()
				return nil
			}
			if len(batch) > 1000 {
				logrus.Warnf("Very large batch of file changes detected: %d files. This may impact performance.", len(batch))
				options.LogTo.Log(api.WatchLogger, "Large batch of file changes detected. If you just switched branches, this is expected.")
			}
			start := time.Now()
			logrus.Debugf("batch start: count[%d]", len(batch))
			err := s.handleWatchBatch(ctx, project, options, batch, rules, syncer)
			if err != nil {
				logrus.Warnf("Error handling changed files: %v", err)
				// If context was canceled, exit immediately
				if ctx.Err() != nil {
					_ = watcher.Close()
					return ctx.Err()
				}
			}
			logrus.Debugf("batch complete: duration[%s] count[%d]", time.Since(start), len(batch))
		}
	}
}

func loadDevelopmentConfig(service types.ServiceConfig, project *types.Project) (*types.DevelopConfig, error) {
	var config types.DevelopConfig

Review comment (suggestion):
`WatchLogger` is used to provide end-user message on the TUI, we should not refer to technical / implementation details

Code after:

func (s *composeService) watchEvents(ctx context.Context, project *types.Project, options api.WatchOptions, watcher watch.Notify, syncer sync.Syncer, rules []watchRule) error {
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	// debounce and group filesystem events so that we capture IDE saving many files as one "batch" event
	batchEvents := watch.BatchDebounceEvents(ctx, s.clock, watcher.Events())

	for {
		select {
		case <-ctx.Done():
			options.LogTo.Log(api.WatchLogger, "Watch disabled")
			// Ensure watcher is closed to release resources
			_ = watcher.Close()
			return nil
		case err, open := <-watcher.Errors():
			if err != nil {
				options.LogTo.Err(api.WatchLogger, "Watch disabled with errors: "+err.Error())
			}
			if open {
				continue
			}
			_ = watcher.Close()
			return err
		case batch, ok := <-batchEvents:
			if !ok {
				options.LogTo.Log(api.WatchLogger, "Watch disabled")
				_ = watcher.Close()
				return nil
			}
			if len(batch) > 1000 {
				logrus.Warnf("Very large batch of file changes detected: %d files. This may impact performance.", len(batch))
				options.LogTo.Log(api.WatchLogger, "Large batch of file changes detected. If you just switched branches, this is expected.")
			}
			start := time.Now()
			logrus.Debugf("batch start: count[%d]", len(batch))
			err := s.handleWatchBatch(ctx, project, options, batch, rules, syncer)
			if err != nil {
				logrus.Warnf("Error handling changed files: %v", err)
				// If context was canceled, exit immediately
				if ctx.Err() != nil {
					_ = watcher.Close()
					return ctx.Err()
				}
			}
			logrus.Debugf("batch complete: duration[%s] count[%d]", time.Since(start), len(batch))
		}
	}
}

func loadDevelopmentConfig(service types.ServiceConfig, project *types.Project) (*types.DevelopConfig, error) {