func (ss *SNSServer) DnsReady() (e error) {
	if ss.SOAProvider == "" {
		return nil
	}
	var (
		ctx    context.Context
		cancel context.CancelFunc
	)
	if ss.waitForDns > 0 {
		ctx, cancel = context.WithTimeout(context.Background(), ss.waitForDns)
	} else {
		ctx, cancel = context.WithCancel(context.Background())
	}
	defer cancel()
	client := dns.Client{
		Net: "tcp",  
		Dialer: &net.Dialer{
			Timeout: ss.waitForDns,
		},
	}
	msg := dns.Msg{}
	msg.SetQuestion(strings.SplitN(ss.SelfUrl.Host, ":", 2)[0]+".", dns.TypeANY)
	defer cancel()
	var check = func() <-chan struct{} {
		var channel = make(chan struct{})
		go func(c chan struct{}) {
			var (
				err      error
				response *dns.Msg
			)
			for {
				response, _, err = client.Exchange(&msg, ss.SOAProvider)
				if err == nil && response != nil && response.Rcode == dns.RcodeSuccess && len(response.Answer) > 0 {
					c <- struct{}{}
					ss.metrics.DnsReady.Add(1.0)
					return
				}
				ss.metrics.DnsReadyQueryCount.Add(1.0)
				ss.debugLog.Log(logging.MessageKey(), "checking if server's DNS is ready",
					"endpoint", strings.SplitN(ss.SelfUrl.Host, ":", 2)[0]+".", logging.ErrorKey(), err, "response", response)
				time.Sleep(time.Second)
			}
		}(channel)
		return channel
	}
	select {
	case <-check():
	case <-ctx.Done():
		e = ctx.Err()
	}
	return
}
DnsReady blocks until the primary server's DNS is up and running or
until the timeout is reached
if timeout value is 0s it will try forever
package aws
import (
	"context"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"sync/atomic"
	"time"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/gorilla/mux"
	"github.com/miekg/dns"
	"github.com/spf13/viper"
	"github.com/xmidt-org/webpa-common/v2/logging"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sns"
	"github.com/aws/aws-sdk-go/service/sns/snsiface"
)
type AWSConfig struct {
	AccessKey string    `json:"accessKey"`
	SecretKey string    `json:"secretKey"`
	Env       string    `json:"env"`
	Sns       SNSConfig `json:"sns"`
}
type SNSConfig struct {
	Protocol    string `json:"protocol"`
	Region      string `json:"region"`
	TopicArn    string `json:"topicArn"`
	UrlPath     string `json:"urlPath"`  
	AwsEndpoint string `json:"awsEndpoint"`
}
type SNSServer struct {
	Config          AWSConfig
	subscriptionArn atomic.Value
	SVC             snsiface.SNSAPI
	SelfUrl         *url.URL
	SOAProvider     string
	SNSValidator
	notificationData     chan string
	channelSize          int64
	channelClientTimeout time.Duration
	errorLog                    log.Logger
	debugLog                    log.Logger
	metrics                     AWSMetrics
	snsNotificationReceivedChan chan int
	waitForDns                  time.Duration
}
type Notifier interface {
	Initialize(*mux.Router, *url.URL, string, http.Handler, log.Logger, AWSMetrics, func() time.Time)
	PrepareAndStart()
	Subscribe()
	PublishMessage(string) error
	Unsubscribe(string)
	NotificationHandle(http.ResponseWriter, *http.Request) []byte
	ValidateSubscriptionArn(string) bool
	SNSNotificationReceivedCounter(int)
	DnsReady() error
}
func NewSNSServer(v *viper.Viper) (ss *SNSServer, err error) {
	var cfg *AWSConfig
	if cfg, err = NewAWSConfig(v); err != nil {
		return nil, err
	}
	cred := credentials.NewStaticCredentials(cfg.AccessKey, cfg.SecretKey, "")
	sess, aws_err := session.NewSession(&aws.Config{
		Region:      aws.String(cfg.Sns.Region),
		Endpoint:    aws.String(cfg.Sns.AwsEndpoint),
		Credentials: cred,
	})
	if aws_err != nil {
		return nil, aws_err
	}
	svc := sns.New(sess)
	ss = &SNSServer{
		Config:               *cfg,
		SVC:                  svc,
		channelSize:          50,
		channelClientTimeout: 30 * time.Second,
	}
	if v != nil && v.IsSet("waitForDns") {
		ss.waitForDns = v.GetDuration("waitForDns")
	}
	if v != nil && v.IsSet("sns.channelSize") {
		ss.channelSize = v.GetInt64("sns.channelSize")
	}
	if v != nil && v.IsSet("sns.channelClientTimeout") {
		ss.channelClientTimeout = v.GetDuration("sns.channelClientTimeout")
	}
	ss.SNSValidator = NewSNSValidator()
	return ss, nil
}
func NewNotifier(v *viper.Viper) (Notifier, error) {
	return NewSNSServer(v)
}
func (ss *SNSServer) Initialize(rtr *mux.Router, selfUrl *url.URL, soaProvider string,
	handler http.Handler, logger log.Logger, metrics AWSMetrics, now func() time.Time) {
	if rtr == nil {
		rtr = mux.NewRouter()
	}
	if now == nil {
		now = time.Now
	}
	var urlPath string
	if strings.HasSuffix(ss.Config.Sns.UrlPath, "/") {
		urlPath = fmt.Sprint(ss.Config.Sns.UrlPath, now().Unix())
	} else {
		urlPath = fmt.Sprint(ss.Config.Sns.UrlPath, "/", now().Unix())
	}
	if selfUrl != nil {
		ss.SelfUrl = selfUrl
		ss.SelfUrl.Path = urlPath
	} else {
		ss.SelfUrl = &url.URL{
			Scheme: "http",
			Host:   "host:10000",
			Path:   urlPath,
		}
	}
	ss.SOAProvider = soaProvider
	ss.notificationData = make(chan string, ss.channelSize)
	if logger == nil {
		logger = logging.DefaultLogger()
	}
	ss.errorLog = log.WithPrefix(logger, level.Key(), level.ErrorValue())
	ss.debugLog = log.WithPrefix(logger, level.Key(), level.DebugValue())
	ss.metrics = metrics
	ss.snsNotificationReceivedChan = ss.SNSNotificationReceivedInit()
	ss.debugLog.Log("selfURL", ss.SelfUrl.String(), "protocol", ss.SelfUrl.Scheme)
	ss.SetSNSRoutes(urlPath, rtr, handler)
}
func (ss *SNSServer) PrepareAndStart() {
	ss.Subscribe()
}