vbauerster / mpb

multi progress bar for Go cli applications
The Unlicense
2.29k stars 123 forks source link

Bar dupes when adding new bar #139

Open Bios-Marcel opened 4 months ago

Bios-Marcel commented 4 months ago

So, for some reason my bar is duplicating. It always happens during the same situation. My assumption is that it is a race condition. But adding locks around all calls that touch the bar didn't help.

So, am I fundamentally missunderstanding something or could it be a bug?

I can try to make a minimally reproducable example and test in on different terminals and distros if you want.

This case happened on Windows 11, Powershell Core, Wezterm.

https://github.com/vbauerster/mpb/assets/19377618/467d1369-cbdb-4c2e-bb6f-9aac252b92d0

    progressBars := mpb.New()
LOOP:
    for {
        select {
        case response, open := <-responses:
            if !open && response == nil && extract != nil {
                // Close extract and let it finish tasks, as its buffered.
                close(extract)
                extract = nil
                continue LOOP
            }

            bar := progressBars.AddBar(100,
                mpb.PrependDecorators(
                    decor.Name(
                        "Downloading: "+filepath.Base(response.Request.URL().String()),
                        decor.WC{C: decor.DindentRight | decor.DextraSpace},
                    ),
                    decor.OnComplete(decor.AverageETA(decor.ET_STYLE_GO), "done"),
                ),
                mpb.AppendDecorators(decor.Percentage()),
            )
            go func() {
                ticker := time.NewTicker(200 * time.Millisecond)
                defer ticker.Stop()
                for {
                    select {
                    case <-ticker.C:
                        bar.SetCurrent(int64(response.Progress() * 100))
                    case <-response.Done:

                        if err := response.Err(); err != nil {
                            bar.Abort(true)
                            errChan <- fmt.Errorf("error during download: %w", err)
                        } else {
                            bar.SetCurrent(100)
                        }

                        extract <- response.Request.Context().Value("item").(Downloadable)
                        return
                    }
                }
            }()
        case err := <-errChan:
            return err
        case downloadedFile, open := <-extract:
            if !open {
                break LOOP
            }

            bar := progressBars.AddBar(100,
                mpb.PrependDecorators(
                    decor.Name(
                        "Extracting: "+filepath.Base(downloadedFile.URL),
                        decor.WC{C: decor.DindentRight | decor.DextraSpace},
                    ),
                    decor.OnComplete(decor.AverageETA(decor.ET_STYLE_GO), "done"),
                ),
                mpb.AppendDecorators(decor.Percentage()),
            )
            for i := 0; i < 10; i++ {
                time.Sleep(200 * time.Millisecond)
                bar.IncrBy(10)
            }

            if err := scoop.extract(app, resolvedApp, cacheDir, versionDir, downloadedFile, arch); err != nil {
                return fmt.Errorf("error extracting file: %w", err)
            }
        }
    }

    progressBars.Shutdown()
vbauerster commented 4 months ago

This case happened on Windows 11, Powershell Core, Wezterm.

Is any example in particular this one works as expected in your environment? If answer is yes, then try to use (*mpb.Progress).Wait() instead of Shutdown().