func (c Client) runBackend(carbonAddr string) {
	retFile := path.Join(c.Conf.RetryDir, carbonAddr)
	chanLock.Lock()
	monChannel := c.monChannels[carbonAddr]
	mainChannel := c.mainChannels[carbonAddr]
	chanLock.Unlock()
	for ; ; time.Sleep(time.Duration(c.Conf.ClientSendInterval) * time.Second) {
		var connectionFailed bool
		conn, err := net.DialTimeout("tcp", carbonAddr, time.Duration(c.Conf.ConnectTimeout)*time.Second)
		if err != nil {
			c.Lc.lg.Println("Can not connect to graphite server: ", err.Error())
			c.saveChannelToRetry(monChannel, len(monChannel), carbonAddr)
			c.saveChannelToRetry(mainChannel, len(mainChannel), carbonAddr)
			c.removeOldDataFromRetryFile(carbonAddr)
			continue
		}
		err = conn.SetWriteDeadline(time.Now().Add(time.Duration(c.Conf.ClientSendInterval-c.Conf.ConnectTimeout-1) * time.Second))
		if err != nil {
			c.Lc.lg.Println("Can not set deadline for connection: ", err.Error())
			connectionFailed = true
		}
		if !connectionFailed {
			retryFileMetrics, _ := readMetricsFromFile(retFile)
			for numOfMetricFromFile, metricFromFile := range retryFileMetrics {
				if numOfMetricFromFile < c.Lc.mainBufferSize {
					err = c.tryToSendToGraphite(metricFromFile, carbonAddr, conn)
					if err != nil {
						c.Lc.lg.Printf("Error happened in the middle of writing retry metrics. Resaving %d metrics\n", len(retryFileMetrics[numOfMetricFromFile:]))
						c.saveSliceToRetry(retryFileMetrics[numOfMetricFromFile:], carbonAddr)
						connectionFailed = true
						break
					} else {
						c.Mon.Increase(&c.Mon.clientStat[carbonAddr].fromRetry, 1)
					}
				} else {
					c.Lc.lg.Printf("Can read only %d metrics from %s. Rest %d will be kept for the next run", numOfMetricFromFile, retFile, len(retryFileMetrics[numOfMetricFromFile:]))
					c.saveSliceToRetry(retryFileMetrics[numOfMetricFromFile:], carbonAddr)
					break
				}
			}
		}
		bufSize := len(monChannel)
		if !connectionFailed {
			for i := 0; i < bufSize; i++ {
				err = c.tryToSendToGraphite(<-monChannel, carbonAddr, conn)
				if err != nil {
					c.Lc.lg.Println("Error happened in the middle of writing monitoring metrics. Saving...")
					c.saveChannelToRetry(monChannel, bufSize-i, carbonAddr)
					connectionFailed = true
					break
				}
			}
		} else {
			c.saveChannelToRetry(monChannel, bufSize, carbonAddr)
		}
		bufSize = len(mainChannel)
		if !connectionFailed {
			for processedMainBuff := 0; processedMainBuff < bufSize; processedMainBuff = processedMainBuff + 1 {
				metric := <-mainChannel
				err = c.tryToSendToGraphite(metric, carbonAddr, conn)
				if err != nil {
					c.Lc.lg.Printf("Error happened in the middle of writing metrics. Saving %d metrics\n", bufSize-processedMainBuff)
					c.saveChannelToRetry(mainChannel, bufSize-processedMainBuff, carbonAddr)
					break
				}
			}
		} else {
			c.saveChannelToRetry(mainChannel, bufSize, carbonAddr)
		}
		conn.Close()
	}
}
Run go routine per carbon server to:
1) Send data from retryFile to a carbon
2) Send metrics from monitoring channel to a carbon
3) Send metrics from the main channel to carbon

And save everything to the retryFile on any error
package grafsy
import (
	"log"
	"net"
	"os"
	"path"
	"strings"
	"sync"
	"time"
)
type Client struct {
	Conf *Config
	Lc *LocalConfig
	Mon *Monitoring
	monChannels map[string]chan string
	mainChannels map[string]chan string
}
var chanLock sync.Mutex
func (c Client) createRetryDir() error {
	err := os.MkdirAll(c.Conf.RetryDir, 0750)
	return err
}
func (c Client) saveSliceToRetry(metrics []string, carbonAddr string) error {
	c.Lc.lg.Printf("Resaving %d metrics back to the retry-file", len(metrics))
	retFile := path.Join(c.Conf.RetryDir, carbonAddr)
	f, err := os.OpenFile(retFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
	if err != nil {
		c.Lc.lg.Println(err)
		c.Mon.Increase(&c.Mon.clientStat[carbonAddr].dropped, len(metrics))
		return err
	}
	defer f.Close()
	dropped := 0
	for _, metric := range metrics {
		_, err = f.WriteString(metric + "\n")
		if err != nil {
			c.Lc.lg.Println(err)
			dropped++
		}
	}
	if dropped > 0 {
		c.Mon.Increase(&c.Mon.clientStat[carbonAddr].dropped, dropped)
	}
	return c.removeOldDataFromRetryFile(carbonAddr)
}
func (c Client) saveChannelToRetry(ch chan string, size int, carbonAddr string) {
	if size == 0 {
		size = len(ch)
	}
	c.Lc.lg.Printf("Saving %d metrics from channel to the retry-file", size)
	retFile := path.Join(c.Conf.RetryDir, carbonAddr)
	f, err := os.OpenFile(retFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
	if err != nil {
		c.Lc.lg.Println(err.Error())
	}
	defer f.Close()
	dropped, saved := 0, 0
	for i := 0; i < size; i++ {
		_, err = f.WriteString(<-ch + "\n")
		if err != nil {
			dropped++
			c.Lc.lg.Println(err.Error())
		} else {
			saved++
		}
	}
	if dropped > 0 {
		c.Mon.Increase(&c.Mon.clientStat[carbonAddr].dropped, dropped)
	}
	if saved > 0 {
		c.Mon.Increase(&c.Mon.clientStat[carbonAddr].saved, saved)
	}
	c.removeOldDataFromRetryFile(carbonAddr)
}
func (c Client) removeOldDataFromRetryFile(carbonAddr string) error {
	retFile := path.Join(c.Conf.RetryDir, carbonAddr)
	currentLinesInFile := getSizeInLinesFromFile(retFile)
	if currentLinesInFile > c.Lc.fileMetricSize {
		c.Lc.lg.Printf("I can not save to %s more, than %d. I will have to drop the rest (%d)",
			retFile, c.Lc.fileMetricSize, currentLinesInFile-c.Lc.fileMetricSize)
		wholeFile, _ := readMetricsFromFile(retFile)
		return c.saveSliceToRetry(wholeFile[:c.Lc.fileMetricSize], carbonAddr)
	}
	return nil
}
func (c *Client) tryToSendToGraphite(metric string, carbonAddr string, conn net.Conn) error {
	metric = strings.Replace(metric, "HOSTNAME", c.Lc.hostname, -1)
	_, err := conn.Write([]byte(metric + "\n"))
	if err != nil {
		c.Lc.lg.Println("Write to server failed:", err.Error())
		return err
	}
	c.Mon.Increase(&c.Mon.clientStat[carbonAddr].sent, 1)
	return nil
}