hunk.code_window: 	POST_SYSTEM_GENERIC        = "system_generic"
   	POST_JOIN_LEAVE            = "system_join_leave"
   	POST_HEADER_CHANGE         = "system_header_change"
   	POST_EPHEMERAL             = "system_ephemeral"
   )
  
hunk.labels: keep keep add keep keep keep
hunk.after_edit: 	POST_CHANNEL_DELETED       = "system_channel_deleted"
  
hunk.file_path: model/post.go
hunk.type: add
file: package aws
  
  import (
  	"math"
  	"net"
  	"net/http"
  	"time"
  )
  
  type RetryableFunc func(*http.Request, *http.Response, error) bool
  type WaitFunc func(try int)
  type DeadlineFunc func() time.Time
  
  type ResilientTransport struct {
  	// Timeout is the maximum amount of time a dial will wait for
  	// a connect to complete.
  	//
  	// The default is no timeout.
  	//
  	// With or without a timeout, the operating system may impose
  	// its own earlier timeout. For instance, TCP timeouts are
  	// often around 3 minutes.
  	DialTimeout time.Duration
  
  	// MaxTries, if non-zero, specifies the number of times we will retry on
  	// failure. Retries are only attempted for temporary network errors or known
  	// safe failures.
  	MaxTries    int
  	Deadline    DeadlineFunc
  	ShouldRetry RetryableFunc
  	Wait        WaitFunc
  	transport   *http.Transport
  }
  
  // Convenience method for creating an http client
  func NewClient(rt *ResilientTransport) *http.Client {
  	rt.transport = &http.Transport{
  		Dial: func(netw, addr string) (net.Conn, error) {
  			c, err := net.DialTimeout(netw, addr, rt.DialTimeout)
  			if err != nil {
  				return nil, err
  			}
  			c.SetDeadline(rt.Deadline())
  			return c, nil
  		},
  		Proxy: http.ProxyFromEnvironment,
  	}
  	// TODO: Would be nice is ResilientTransport allowed clients to initialize
  	// with http.Transport attributes.
  	return &http.Client{
  		Transport: rt,
  	}
  }
  
  var retryingTransport = &ResilientTransport{
  	Deadline: func() time.Time {
  		return time.Now().Add(5 * time.Second)
  	},
  	DialTimeout: 10 * time.Second,
  	MaxTries:    3,
  	ShouldRetry: awsRetry,
  	Wait:        ExpBackoff,
  }
  
  // Exported default client
  var RetryingClient = NewClient(retryingTransport)
  
  func (t *ResilientTransport) RoundTrip(req *http.Request) (*http.Response, error) {
  	return t.tries(req)
  }
  
  // Retry a request a maximum of t.MaxTries times.
  // We'll only retry if the proper criteria are met.
  // If a wait function is specified, wait that amount of time
  // In between requests.
  func (t *ResilientTransport) tries(req *http.Request) (res *http.Response, err error) {
  	for try := 0; try < t.MaxTries; try += 1 {
  		res, err = t.transport.RoundTrip(req)
  
  		if !t.ShouldRetry(req, res, err) {
  			break
  		}
  		if res != nil {
  			res.Body.Close()
  		}
  		if t.Wait != nil {
  			t.Wait(try)
  		}
  	}
  
  	return
  }
  
  func ExpBackoff(try int) {
  	time.Sleep(100 * time.Millisecond *
  		time.Duration(math.Exp2(float64(try))))
  }
  
  func LinearBackoff(try int) {
  	time.Sleep(time.Duration(try*100) * time.Millisecond)
  }
  
  // Decide if we should retry a request.
  // In general, the criteria for retrying a request is described here
  // http://docs.aws.amazon.com/general/latest/gr/api-retries.html
  func awsRetry(req *http.Request, res *http.Response, err error) bool {
  	retry := false
  
  	// Retry if there's a temporary network error.
  	if neterr, ok := err.(net.Error); ok {
  		if neterr.Temporary() {
  			retry = true
  		}
  	}
  
  	// Retry if we get a 5xx series error.
  	if res != nil {
  		if res.StatusCode >= 500 && res.StatusCode < 600 {
  			retry = true
  		}
  	}
  
  	return retry
  }
  