<p>I use the following code which works and installs helm charts.
I got a list of charts and it installs each chart (via loop) and wait (<code>upgradeAction.Wait = true</code>, see below ) that the chart is up and running (using the <code>wait=true</code> flag of the helm) and then install the next one, the problem is that it takes a <strong>lot of time</strong> to wait that each chart is up-and-running <strong>and just then proceed to the next one</strong>, Is there a way to install <strong>all in parallel</strong> and just verify at the end (of all the charts installations)  that it works (like how the wait works but for list of charts).</p>
<p>Here is the code:</p>
<pre><code>mpfile, err := ioutil.TempFile(kp, kcp)
if err != nil {
    log.Error(err, &quot;error&quot;)
}

defer os.Remove(tmpfile.Name()) 

if _, err := tmpfile.Write(cfg); err != nil {
    return err
}
if err := tmpfile.Close(); err != nil {
    return err
}

kcfgFilePath := tmpfile.Name()
settings := cli.New()
ac := new(action.Configuration)
clientGetter := genericclioptions.NewConfigFlags(false)
clientGetter.KubeConfig = &amp;kcfgFilePath

for _, chartInstallation := range charts {
    chart, err := loader.Load(chartInstallation.Path)
    if err != nil {
        return err
    }

    releaseName := releaseName + &quot;-&quot; + chartInstallation.Name
    if err := ac.Init(clientGetter, settings.Namespace(), os.Getenv(&quot;HELM_DRIVER&quot;), func(format string, v ...interface{}) {
        
    }); err != nil {
        return err
    }
    releasePresent := true
    statusAction := action.NewStatus(ac)
    status, err := statusAction.Run(releaseName)
    if err != nil {
        if strings.Contains(err.Error(), driver.ErrReleaseNotFound.Error()) {
            releasePresent = false
        } else {
            return err
        }
    }

    if !releasePresent {
        // install chart
        installAction := action.NewInstall(ac)
        installAction.CreateNamespace = true
        installAction.Namespace = chartInstallation.Namespace
        installAction.ReleaseName = releaseName

        _, err := installAction.Run(chart, nil)
        if err != nil {
            return err
        }
        log.Info(&quot;chart installed: &quot;, &quot;releaseName&quot;, releaseName)
    }

    if status != nil {
        if releasePresent &amp;&amp; status.Info.Status.String() == release.StatusFailed.String() { 
            upgradeAction := action.NewUpgrade(ac)
            // HERE IT WAIT FOR THE CHART TO VERIFY THAT EVERYTHING IS UP
            upgradeAction.Wait = true
            upgradeAction.ReuseValues = false
            upgradeAction.Recreate = false
            _, err := upgradeAction.Run(releaseName, chart, nil)
            if err != nil {
                return err
            }
        }
    }
}
</code></pre>
<p>If I change it to  <code>upgradeAction.Wait = false</code> , It starts to install all the charts without waiting to each one health checks, however not sure how can I verify it at the end of all the charts installations</p>

<p>You could start goroutines for each chart you're installing (wrapping chart install code inside go routines) and then use <code>sync.WaitGroup</code> to wait all goroutines to finish. Something like this:</p>
<pre class="lang-golang prettyprint-override"><code>package main

import (
    &quot;fmt&quot;
    &quot;os&quot;
    &quot;strings&quot;
    &quot;sync&quot;
)

func main() {
    kcfgFilePath := tmpfile.Name()
    settings := cli.New()
    ac := new(action.Configuration)
    clientGetter := genericclioptions.NewConfigFlags(false)
    clientGetter.KubeConfig = &amp;kcfgFilePath
    var wg sync.WaitGroup

    for _, chartInstallation := range charts {
        wg.Add(1)
        go installChart(&amp;wg, chartInstallation.Path)
    }

    fmt.Println(&quot;Installing...&quot;)
    wg.Wait()
    fmt.Println(&quot;Installed!&quot;)
}

func installChart(wg *sync.WaitGroup, chartInstallationPath string) error {
    defer wg.Done()

    chart, err := loader.Load(chartInstallationPath)
    if err != nil {
        return err
    }

    releaseName := releaseName + &quot;-&quot; + chartInstallation.Name
    if err := ac.Init(clientGetter, settings.Namespace(), os.Getenv(&quot;HELM_DRIVER&quot;), func(format string, v ...interface{}) {

    }); err != nil {
        return err
    }
    releasePresent := true
    statusAction := action.NewStatus(ac)
    status, err := statusAction.Run(releaseName)
    if err != nil {
        if strings.Contains(err.Error(), driver.ErrReleaseNotFound.Error()) {
            releasePresent = false
        } else {
            return err
        }
    }

    if !releasePresent {
        // install chart
        installAction := action.NewInstall(ac)
        installAction.CreateNamespace = true
        installAction.Namespace = chartInstallation.Namespace
        installAction.ReleaseName = releaseName

        _, err := installAction.Run(chart, nil)
        if err != nil {
            return err
        }
        log.Info(&quot;chart installed: &quot;, &quot;releaseName&quot;, releaseName)
    }

    if status != nil {
        if releasePresent &amp;&amp; status.Info.Status.String() == release.StatusFailed.String() {
            upgradeAction := action.NewUpgrade(ac)
            // HERE IT WAIT FOR THE CHART TO VERIFY THAT EVERYTHING IS UP
            upgradeAction.Wait = true
            upgradeAction.ReuseValues = false
            upgradeAction.Recreate = false
            _, err := upgradeAction.Run(releaseName, chart, nil)
            if err != nil {
                return err
            }
        }
    }
}
</code></pre>
<p>Here's a good resource for that: <a href="https://goinbigdata.com/golang-wait-for-all-goroutines-to-finish/" rel="nofollow noreferrer">https://goinbigdata.com/golang-wait-for-all-goroutines-to-finish/</a></p>
