I have this current function that originally was not context aware.
func (s *Service) ChunkUpload(r *multipart.Reader) error {
chunk, err := s.parseChunk(r)
if err != nil {
return fmt.Errorf("failed parsing chunk %w", err)
}
if err := os.MkdirAll(chunk.UploadDir, 02750); err != nil {
return err
}
if err := s.saveChunk(chunk); err != nil {
return fmt.Errorf("failed saving chunk %w", err)
}
return nil
}
I've updated it's method call to now take a context.Context
as its first argument. My main goal is to terminate and return the function as soon as the context is cancelled.
My initial implementation was this.
func (s *Service) ChunkUpload(ctx context.Context, r *multipart.Reader) error {
errCh := make(chan error)
go func() {
chunk, err := s.parseChunk(r)
if err != nil {
errCh <- fmt.Errorf("failed parsing chunk %w", err)
return
}
if err := os.MkdirAll(chunk.UploadDir, 02750); err != nil {
errCh <- err
return
}
if err := s.saveChunk(chunk); err != nil {
errCh <- fmt.Errorf("failed saving chunk %w", err)
return
}
}()
select {
case err := <-errCh:
return err
case <-ctx.Done():
return ctx.Err()
}
}
However, as I thought about the execution of the code I realized that this doesn't achieve my goal. Since all the function's logic is in a separate go routine even if context gets cancelled and I return ChunkUpload
early the code within the go routine will continue to execute thus not really making a difference from the original code.
The next though was okay just pass a context to all inner functions like s.parseChunk
and s.saveChunk
but this option also doesn't seem right as I would need to implement cancellations in each function. What would be the proper way to refactor this original function to be context aware and terminate as soon as a context is cancelled?
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…