Documentation
¶
Overview ¶
Example ¶
Example demonstrates basic usage of nspool with a resolver pool.
// Create pool with resolver addresses
nsp := nspool.NewFromPoolSlice([]string{"1.1.1.1:53", "8.8.8.8:53"})
// Configure health checking
nsp.SetHealthDomainSuffix("example.com")
nsp.SetMinResolvers(1)
// Perform initial health check
if err := nsp.Refresh(); err != nil {
log.Fatal(err)
}
// Create DNS query
msg := new(dns.Msg)
msg.SetQuestion("github.com.", dns.TypeA)
// Query using the pool
response, _, err := nsp.Exchange(msg)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Received %d answers\n", len(response.Answer))
Index ¶
- Variables
- func AddPort(addr string) string
- func DefaultHealthCheckFunction(ans dns.Msg, t time.Duration, resolver string, p *Pool) bool
- func DefaultHealthLabelGenerator() string
- func DefaultRefreshPostHook(p *Pool)
- func DefaultRefreshPreHook(p *Pool) bool
- type DNSClientLike
- type FileArray
- type HealthCheckFunction
- type HealthLabelGenerator
- type Pool
- func (p *Pool) AutoRefresh(t time.Duration)
- func (p *Pool) AvailableCount() int
- func (p *Pool) AvailableResolvers() []string
- func (p *Pool) Debug() bool
- func (p *Pool) Exchange(m *dns.Msg) (*dns.Msg, time.Duration, error)
- func (p *Pool) ExchangeContext(ctx context.Context, m *dns.Msg) (*dns.Msg, time.Duration, error)
- func (p *Pool) ExchangeWeighted(m *dns.Msg) (*dns.Msg, time.Duration, error)
- func (p *Pool) ExchangeWeightedContext(ctx context.Context, m *dns.Msg) (*dns.Msg, time.Duration, error)
- func (p *Pool) GetRandomResolver() (string, error)
- func (p *Pool) GetRandomResolverWeighted() (string, error)
- func (p *Pool) GetResolverStats() []ResolverStats
- func (p *Pool) HealthCheckFunction() HealthCheckFunction
- func (p *Pool) HealthCheckQType() uint16
- func (p *Pool) HealthCheckWorkerCount() int
- func (p *Pool) HealthDomainSuffix() string
- func (p *Pool) InstallSignalHandler(sig os.Signal)
- func (p *Pool) LastRefreshed() time.Time
- func (p *Pool) Logger() *logrus.Logger
- func (p *Pool) MaxQueryRetries() int
- func (p *Pool) MinResolvers() int
- func (p *Pool) QuietResolverStateChange() bool
- func (p *Pool) RecordResolverQuery(resolver string, success bool)
- func (p *Pool) Refresh() error
- func (p *Pool) RefreshNameServerTimeout(t time.Duration)
- func (p *Pool) RefreshPostHook() RefreshPostHook
- func (p *Pool) RefreshPreHook() RefreshPreHook
- func (p *Pool) SetDebug(enabled bool)
- func (p *Pool) SetHealthCheckFunction(fn HealthCheckFunction)
- func (p *Pool) SetHealthCheckQType(qtype uint16)
- func (p *Pool) SetHealthCheckWorkerCount(count int)
- func (p *Pool) SetHealthDomainSuffix(suffix string)
- func (p *Pool) SetLogger(l *logrus.Logger)
- func (p *Pool) SetMaxQueryRetries(retries int)
- func (p *Pool) SetMinResolvers(min int)
- func (p *Pool) SetQuietResolverStateChange(quiet bool)
- func (p *Pool) SetRefreshPostHook(fn RefreshPostHook)
- func (p *Pool) SetRefreshPreHook(fn RefreshPreHook)
- func (p *Pool) SetResolverCooldownPeriod(period time.Duration)
- func (p *Pool) SetResolverDisableThreshold(threshold float64)
- func (p *Pool) SetResolverErrorThreshold(threshold float64)
- func (p *Pool) StopSignalHandler()
- func (p *Pool) UnavailableCount() int
- func (p *Pool) UnavailableResolvers() []string
- type RefreshPostHook
- type RefreshPreHook
- type ResolverMetrics
- type ResolverStats
Examples ¶
- Package
- DefaultHealthCheckFunction
- DefaultRefreshPostHook
- DefaultRefreshPreHook
- NewFromPoolSlice
- Pool.AutoRefresh
- Pool.ExchangeContext
- Pool.GetRandomResolver
- Pool.SetHealthCheckFunction
- Pool.SetHealthCheckWorkerCount
- Pool.SetLogger
- Pool.SetMaxQueryRetries
- Pool.SetQuietResolverStateChange
- Pool.SetRefreshPostHook
- Pool.SetRefreshPreHook
- Pool.SetRefreshPreHook (Conditional)
Constants ¶
This section is empty.
Variables ¶
var ( // ErrNilPool is returned when methods are invoked against a nil Pool. ErrNilPool = fmt.Errorf("nil pool") // ErrNilDNSClient is returned when the internal DNS Client is nil. ErrNilDNSClient = fmt.Errorf("nil dns client") // ErrNoHcSuffix is returned whenever a health check is required and // there is no HealthDomainSuffix() set. ErrNoHcSuffix = fmt.Errorf("health check domain suffix not set") // ErrInsufficientResolvers is returned when there are not enough available resolvers // to satisfy the minimum resolver requirement. ErrInsufficientResolvers = fmt.Errorf("insufficient available resolvers") // ErrNilHealthCheck is returned when Refresh() is called and the health check // function is nil. ErrNilHealthCheck = fmt.Errorf("nil health check function") // ErrRefreshAbortedByPreHook is returned when the pre-refresh hook returns false, // preventing the refresh operation from proceeding. ErrRefreshAbortedByPreHook = fmt.Errorf("refresh aborted by pre-hook") )
Functions ¶
func AddPort ¶ added in v2.0.4
AddPort ensures a resolver address has a port. If no port is present, it appends the default DNS port :53. This handles both IPv4 and most IPv6 cases using a naive colon check from the end of the string.
This function is useful when working with resolver addresses that may or may not include port numbers.
func DefaultHealthCheckFunction ¶
DefaultHealthCheckFunction provides default health check behaviour, which simply verifies tha the response indicated success. If the debug attribute is enabled and a logger has been provided, it will log data about the response including the resolver that was checked.
Example ¶
ExampleDefaultHealthCheckFunction demonstrates the default health check behavior.
// Create a pool
nsp := nspool.NewFromPoolSlice([]string{"1.1.1.1:53"})
nsp.SetHealthDomainSuffix("example.com")
// The default health check function is used automatically
// It simply verifies the response has RCODE = NOERROR
if err := nsp.Refresh(); err != nil {
log.Fatal(err)
}
fmt.Println("Using default health check")
func DefaultHealthLabelGenerator ¶
func DefaultHealthLabelGenerator() string
DefaultHealthLabelGenerator is the dafault function to generate labels used for resolver health checking. It returns a 16 character ASCII label made up of random characters from a restricted alphabet built into the function. The result of this function will be concatenated with the default suffix to generate the final FQDNs that will be used to test the resolvers.
func DefaultRefreshPostHook ¶ added in v2.0.3
func DefaultRefreshPostHook(p *Pool)
DefaultRefreshPostHook is the default post-refresh hook that does nothing. This function serves as an example and documentation for implementing custom post-refresh hooks.
Example usage:
nsp.SetRefreshPostHook(func(p *nspool.Pool) {
log.Printf("Refresh complete: %d available, %d unavailable",
p.AvailableCount(), p.UnavailableCount())
})
Example ¶
ExampleDefaultRefreshPostHook demonstrates the default post-hook behavior.
// The default post-hook is a no-op
nsp := nspool.NewFromPoolSlice([]string{"1.1.1.1:53"})
nsp.SetHealthDomainSuffix("example.com")
// You can explicitly set it if desired
nsp.SetRefreshPostHook(nspool.DefaultRefreshPostHook)
if err := nsp.Refresh(); err != nil {
log.Fatal(err)
}
fmt.Println("Using default post-hook")
func DefaultRefreshPreHook ¶ added in v2.0.3
DefaultRefreshPreHook is the default pre-refresh hook that always allows the refresh to proceed. This function serves as an example and documentation for implementing custom pre-refresh hooks.
Example usage:
nsp.SetRefreshPreHook(func(p *nspool.Pool) bool {
// Only allow refresh during off-peak hours
hour := time.Now().Hour()
return hour < 8 || hour > 18
})
Example ¶
ExampleDefaultRefreshPreHook demonstrates the default pre-hook behavior.
// The default pre-hook always returns true (allows refresh)
nsp := nspool.NewFromPoolSlice([]string{"1.1.1.1:53"})
nsp.SetHealthDomainSuffix("example.com")
// You can explicitly set it if desired
nsp.SetRefreshPreHook(nspool.DefaultRefreshPreHook)
if err := nsp.Refresh(); err != nil {
log.Fatal(err)
}
fmt.Println("Using default pre-hook")
Types ¶
type DNSClientLike ¶ added in v2.0.5
type DNSClientLike interface {
Exchange(*dns.Msg, string) (*dns.Msg, time.Duration, error)
ExchangeContext(context.Context, *dns.Msg, string) (*dns.Msg, time.Duration, error)
}
DNSClientLike is an interface that should accept dns.Client. This is used to facilitate testing and allowing easier overriding to support special use cases.
type FileArray ¶
type FileArray []string
FileArray is a string slice that can be populated from a file or direct values in configuration. It supports three use cases:
Single file reference: "@/path/to/file[.gz|.bz2|.xz]" -> [lines from file] Each non-empty, non-comment line in the file becomes an element. The file can be optionally compressed with gzip (.gz), bzip2 (.bz2), or xz (.xz) compression - decompression happens automatically.
String slice: ["ns1:53", "ns2:53"] -> ["ns1:53", "ns2:53"] Array values are used directly.
Single string: "ns1:53" -> ["ns1:53"] Single string becomes a one-element slice.
func NewFileArray ¶
NewFileArray creates a FileArray from a string or []string input. If the input is a string starting with "@", it reads from the file. The file can be optionally compressed with gzip (.gz), bzip2 (.bz2), or xz (.xz) compression - decompression happens automatically.
func (FileArray) StringSlice ¶
StringSlice returns the underlying string slice
func (*FileArray) UnmarshalJSON ¶ added in v2.0.2
UnmarshalJSON implements json.Unmarshaler for FileArray
func (*FileArray) UnmarshalTOML ¶ added in v2.0.2
UnmarshalTOML implements the interface for TOML decoding.
func (*FileArray) UnmarshalText ¶ added in v2.0.2
UnmarshalText implements encoding.TextUnmarshaler for FileArray
type HealthCheckFunction ¶
HealthCheckFunction is the signature for the function that powers resolver health check. It receives the DNS response to the health check query, the time it took to get the answer, the resolver address being checked, and a pointer to the nspool that is running the health check. It must return true to indicate a healthy, usable resolver. False marks the resolver as unavailable for use.
type HealthLabelGenerator ¶
type HealthLabelGenerator func() string
HealthLabelGenerator is the signature for a function that generates the label used for resolver health checks. It must return a string that will be used to construct the name that will be queried on each candidate resolver during health checks.
type Pool ¶
type Pool struct {
// Client is a pointer to the dns.Client that will be used for sending all queries.
// This value is automatically set by the constructors to a vainilla dns.Client
// object. It is exposed to allow the caller to further customize behavior.
// Setting this value to nil will cause all operations to return an error.
Client DNSClientLike
// contains filtered or unexported fields
}
Pool represents a new nspool object.
func NewFromPoolSlice ¶
NewFromPoolSlice returns a newly configured Pool primed with the resolvers explicitly provided in the call. All resolvers are initially marked as available. Use Refresh() to validate resolver health if needed.
Example ¶
ExampleNewFromPoolSlice demonstrates creating a pool with explicit resolver addresses.
// Create pool with specific resolvers
nsp := nspool.NewFromPoolSlice([]string{
"1.1.1.1:53",
"8.8.8.8:53",
"9.9.9.9:53",
})
// Configure health checking
nsp.SetHealthDomainSuffix("example.com")
// Perform health check
if err := nsp.Refresh(); err != nil {
log.Fatal(err)
}
fmt.Printf("Available resolvers: %d\n", nsp.AvailableCount())
func NewFromViper ¶
NewFromViper returns a newly configured Pool primed with the resolvers from viper using the provided tag. If the value in viper starts with '@', it will be treated as a file reference and the resolvers will be read from that file. All resolvers are initially marked as available. Use Refresh() to validate resolver health if needed.
func (*Pool) AutoRefresh ¶
AutoRefresh enables automatic refresh of resolver health checks at the interval specified by hcAutoRefreshInterval. The behavior is as follows:
- If hcAutoRefreshInterval is <= 0, automatic refresh is disabled and any existing auto-refresh goroutine is stopped.
- If hcAutoRefreshInterval is > 0, a new goroutine is launched that will periodically call Refresh() at the specified interval.
- Any existing auto-refresh goroutine is stopped before starting a new one.
- The first health check is performed immediately upon enabling auto-refresh.
- All Refresh() errors are logged if a logger is configured.
The auto-refresh goroutine can be stopped by either:
- Calling AutoRefresh with an interval <= 0
- Garbage collecting the Pool (the goroutine will exit automatically)
If you need to manually trigger a refresh while auto-refresh is active, you can still call Refresh() directly at any time.
Example ¶
ExamplePool_AutoRefresh demonstrates automatic periodic health checking.
nsp := nspool.NewFromPoolSlice([]string{"1.1.1.1:53", "8.8.8.8:53"})
nsp.SetHealthDomainSuffix("example.com")
// Perform initial refresh
if err := nsp.Refresh(); err != nil {
log.Fatal(err)
}
// Start auto-refresh every 5 minutes
nsp.AutoRefresh(5 * time.Minute)
// Stop auto-refresh when done
defer nsp.AutoRefresh(0)
// Use the pool for queries...
fmt.Println("Auto-refresh enabled")
func (*Pool) AvailableCount ¶
AvailableCount returns the number of currently available resolvers.
func (*Pool) AvailableResolvers ¶
AvailableResolvers returns a copy of the list of currently available resolvers. The returned slice can be safely modified without affecting the pool's internal state. Returns nil if the pool is nil.
func (*Pool) Exchange ¶
Exchange performs a DNS query using a randomly selected resolver from the pool. It will retry the query up to maxQueryRetries times if a resolver fails to respond. The query will timeout after queryTimeout duration for each attempt. Returns the DNS response, elapsed time, and any error encountered.
func (*Pool) ExchangeContext ¶
ExchangeContext performs a DNS query using a randomly selected resolver from the pool. It will retry the query up to maxQueryRetries times if a resolver fails to respond. The context controls the overall timeout for all retry attempts. Returns the DNS response, elapsed time, and any error encountered.
Example ¶
ExamplePool_ExchangeContext demonstrates DNS queries with context timeout.
nsp := nspool.NewFromPoolSlice([]string{"1.1.1.1:53"})
nsp.SetHealthDomainSuffix("example.com")
if err := nsp.Refresh(); err != nil {
log.Fatal(err)
}
// Create context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Create DNS query
msg := new(dns.Msg)
msg.SetQuestion("github.com.", dns.TypeA)
// Query with context
response, rtt, err := nsp.ExchangeContext(ctx, msg)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Query completed in %v with %d answers\n", rtt, len(response.Answer))
func (*Pool) ExchangeWeighted ¶ added in v2.0.4
ExchangeWeighted performs a DNS query using a weighted randomly selected resolver from the pool. It will retry the query up to maxQueryRetries times if a resolver fails to respond. Resolver selection is weighted based on error rates, with poorly-performing resolvers being less likely to be selected. Returns the DNS response, elapsed time, and any error encountered.
func (*Pool) ExchangeWeightedContext ¶ added in v2.0.4
func (p *Pool) ExchangeWeightedContext(ctx context.Context, m *dns.Msg) (*dns.Msg, time.Duration, error)
ExchangeWeightedContext performs a DNS query using a weighted randomly selected resolver from the pool. It will retry the query up to maxQueryRetries times if a resolver fails to respond. The context controls the overall timeout for all retry attempts. Resolver selection is weighted based on error rates, and query results are automatically recorded for performance tracking. Returns the DNS response, elapsed time, and any error encountered.
func (*Pool) GetRandomResolver ¶
GetRandomResolver returns a randomly selected resolver from the pool of available resolvers. It returns an error if the number of available resolvers is less than the minimum required threshold. The returned resolver address will have `:53` appended if no port is present.
Example ¶
ExamplePool_GetRandomResolver demonstrates getting a resolver address directly.
nsp := nspool.NewFromPoolSlice([]string{"1.1.1.1:53", "8.8.8.8:53"})
nsp.SetHealthDomainSuffix("example.com")
if err := nsp.Refresh(); err != nil {
log.Fatal(err)
}
// Get a random resolver
resolver, err := nsp.GetRandomResolver()
if err != nil {
log.Fatal(err)
}
// Use it directly with dns.Client
client := new(dns.Client)
msg := new(dns.Msg)
msg.SetQuestion("github.com.", dns.TypeA)
response, _, err := client.Exchange(msg, resolver)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Query via %s returned %d answers\n", resolver, len(response.Answer))
func (*Pool) GetRandomResolverWeighted ¶ added in v2.0.4
GetRandomResolverWeighted returns a randomly selected resolver from the pool, taking into account error rates and disabled resolvers. It respects the cooldown period for re-enabling disabled resolvers.
func (*Pool) GetResolverStats ¶ added in v2.0.4
func (p *Pool) GetResolverStats() []ResolverStats
GetResolverStats returns performance statistics for all resolvers that have served at least one query.
func (*Pool) HealthCheckFunction ¶ added in v2.0.2
func (p *Pool) HealthCheckFunction() HealthCheckFunction
HealthCheckFunction returns the current function used to evaluate resolver health. Returns nil if the pool is nil.
func (*Pool) HealthCheckQType ¶
HealthCheckQType returns the DNS query type used for health checks. If not explicitly set, defaults to TypeA.
func (*Pool) HealthCheckWorkerCount ¶ added in v2.0.2
HealthCheckWorkerCount returns the number of worker goroutines used for parallel health checks. A value of 0 or negative will still be returned as-is, but during Refresh operations these values will result in using a single worker. Defaults to 64.
func (*Pool) HealthDomainSuffix ¶
HealthDomainSuffix returns the currently configured health-check domain suffix.
func (*Pool) InstallSignalHandler ¶ added in v2.0.4
InstallSignalHandler sets up a signal handler that logs pool statistics when the specified signal is received. The handler logs the number of total resolvers, available resolvers, and unavailable resolvers. This can be useful for monitoring pool health during long-running operations.
Only one signal handler can be installed at a time. Multiple calls will replace the existing handler with a new one for the specified signal. The signal handler runs in a goroutine until StopSignalHandler() is called or the Pool is garbage collected.
Example:
pool.InstallSignalHandler(syscall.SIGUSR1)
On Unix systems, you can send the signal with: kill -USR1 <pid>
func (*Pool) LastRefreshed ¶
LastRefreshed returns the time of the last successful refresh operation. Returns zero time if no refresh has been performed or if the pool is nil.
func (*Pool) Logger ¶ added in v2.0.2
Logger returns the current logger used by the pool. Returns nil if no logger is set or if the pool is nil.
func (*Pool) MaxQueryRetries ¶ added in v2.0.2
MaxQueryRetries returns the maximum number of times a query will be retried with different resolvers before giving up. This affects both health checks and regular DNS queries. A value of 0 means only one attempt will be made (no retries).
func (*Pool) MinResolvers ¶
MinResolvers returns the minimum number of resolvers that must be available for the pool to be considered operational. A value of 0 means no minimum is required.
func (*Pool) QuietResolverStateChange ¶ added in v2.0.6
QuietResolverStateChange returns the current value of the quiet resolver state change flag. When true, only suspension (removal from pool) and reinstatement (addition back to pool) events are logged. Weight reduction (demotion) events are suppressed.
func (*Pool) RecordResolverQuery ¶ added in v2.0.4
RecordResolverQuery records the result of a query to a specific resolver. This is used to track resolver performance and automatically disable poorly performing resolvers based on configured thresholds.
func (*Pool) Refresh ¶
Refresh implements health checking of the candidate resolvers. It will iterate over each candidate through a workerpool issuing queries in parallel fashion. Candidate resolvers that pass the test will be added to the availableResolvers slice while failing resolvers will be added to the unavailableResolvers slice.
The whole Refresh() cycle is protected so there can only be one Refresh() running at a time. Concurrent attempts will serialize. Refresh() will return an error if HealthDomainSuffix() has not been called with a valid domain name suffix.
If a pre-refresh hook is set, it will be called before the refresh starts. If the hook returns false, the refresh is aborted and ErrRefreshAbortedByPreHook is returned.
If a post-refresh hook is set, it will be called after the refresh completes, regardless of success or failure (except when aborted by the pre-hook).
If a logger has been set, significant events will be logged as Info(). If the debug flag has been set via SetDebug(), more detailed logging will be provided via Debug().
func (*Pool) RefreshNameServerTimeout ¶
RefreshNameServerTimeout sets the timeout interval to use when performing resolver health checks. Will refuse negative timeout intervals.
func (*Pool) RefreshPostHook ¶ added in v2.0.3
func (p *Pool) RefreshPostHook() RefreshPostHook
RefreshPostHook returns the current post-refresh hook function. Returns nil if no hook is set or if the pool is nil.
func (*Pool) RefreshPreHook ¶ added in v2.0.3
func (p *Pool) RefreshPreHook() RefreshPreHook
RefreshPreHook returns the current pre-refresh hook function. Returns nil if no hook is set or if the pool is nil.
func (*Pool) SetHealthCheckFunction ¶ added in v2.0.2
func (p *Pool) SetHealthCheckFunction(fn HealthCheckFunction)
SetHealthCheckFunction sets the function that will be used to evaluate resolver health during refresh operations. If nil is provided, the default health check function will be used.
Example ¶
ExamplePool_SetHealthCheckFunction demonstrates using a custom health check function.
nsp := nspool.NewFromPoolSlice([]string{"1.1.1.1:53"})
nsp.SetHealthDomainSuffix("example.com")
// Custom health check that validates response content
customCheck := func(ans dns.Msg, t time.Duration, resolver string, p *nspool.Pool) bool {
// Must respond within 2 seconds
if t > 2*time.Second {
return false
}
// Must have NOERROR response
if ans.Rcode != dns.RcodeSuccess {
return false
}
// Must have at least one answer
if len(ans.Answer) == 0 {
return false
}
return true
}
nsp.SetHealthCheckFunction(customCheck)
if err := nsp.Refresh(); err != nil {
log.Fatal(err)
}
fmt.Printf("Healthy resolvers: %d\n", nsp.AvailableCount())
func (*Pool) SetHealthCheckQType ¶
SetHealthCheckQType sets the DNS query type to be used for health checks.
func (*Pool) SetHealthCheckWorkerCount ¶ added in v2.0.2
SetHealthCheckWorkerCount sets the number of worker goroutines used for parallel health checks. Values of 0 or negative will result in using a single worker. The default is 64. This setting affects the number of concurrent health checks performed during Refresh().
Example ¶
ExamplePool_SetHealthCheckWorkerCount demonstrates configuring health check concurrency.
nsp := nspool.NewFromPoolSlice([]string{
"1.1.1.1:53",
"8.8.8.8:53",
"9.9.9.9:53",
})
nsp.SetHealthDomainSuffix("example.com")
// Use 10 workers for health checks
nsp.SetHealthCheckWorkerCount(10)
if err := nsp.Refresh(); err != nil {
log.Fatal(err)
}
fmt.Printf("Health checks use %d workers\n", nsp.HealthCheckWorkerCount())
func (*Pool) SetHealthDomainSuffix ¶
SetHealthDomainSuffix sets the health-check domain suffix. You must initialize the health-check domain suffix in order for automatic health-check to work. Calling Refresh() without this step will result in simply marking all resolvers as unavailable.
func (*Pool) SetLogger ¶ added in v2.0.2
SetLogger sets the logger to be used for debug and error messages. Pass nil to disable logging.
Example ¶
ExamplePool_SetLogger demonstrates enabling logging with logrus.
nsp := nspool.NewFromPoolSlice([]string{"1.1.1.1:53"})
nsp.SetHealthDomainSuffix("example.com")
// Create and configure logger
logger := logrus.New()
logger.SetLevel(logrus.InfoLevel)
// Enable logging
nsp.SetLogger(logger)
nsp.SetDebug(true)
if err := nsp.Refresh(); err != nil {
log.Fatal(err)
}
fmt.Println("Logging enabled")
func (*Pool) SetMaxQueryRetries ¶ added in v2.0.2
SetMaxQueryRetries sets the maximum number of times a query will be retried with different resolvers before giving up. This affects both health checks and regular DNS queries. A value of 0 means only one attempt will be made (no retries). Negative values are treated as 0.
Example ¶
ExamplePool_SetMaxQueryRetries demonstrates configuring query retry behavior.
nsp := nspool.NewFromPoolSlice([]string{
"1.1.1.1:53",
"8.8.8.8:53",
"9.9.9.9:53",
})
nsp.SetHealthDomainSuffix("example.com")
// Set maximum retries to 5 (up to 6 total attempts)
nsp.SetMaxQueryRetries(5)
if err := nsp.Refresh(); err != nil {
log.Fatal(err)
}
fmt.Printf("Max retries set to %d\n", nsp.MaxQueryRetries())
func (*Pool) SetMinResolvers ¶
SetMinResolvers sets the minimum number of resolvers that must be available for the pool to be considered operational. A value of 0 means no minimum is required. Negative values are treated as 0.
func (*Pool) SetQuietResolverStateChange ¶ added in v2.0.6
SetQuietResolverStateChange sets the quiet resolver state change flag. When set to true, only suspension and reinstatement events are logged. Weight reduction (demotion) events are suppressed, reducing log verbosity during normal operations while still tracking critical state changes.
Example ¶
ExamplePool_SetQuietResolverStateChange demonstrates how to enable quiet mode to suppress verbose demotion messages while still logging critical state changes.
// Create a pool with some resolvers
nsp := nspool.NewFromPoolSlice([]string{"1.1.1.1:53", "8.8.8.8:53"})
// Set up logging
logger := logrus.New()
logger.SetLevel(logrus.InfoLevel)
nsp.SetLogger(logger)
// Configure error thresholds
nsp.SetResolverErrorThreshold(0.05) // 5% error rate triggers weight reduction
nsp.SetResolverDisableThreshold(0.20) // 20% error rate triggers suspension
// Enable quiet mode to suppress demotion messages
// Only suspension and reinstatement events will be logged
nsp.SetQuietResolverStateChange(true)
// Configure health checking
nsp.SetHealthDomainSuffix("example.com")
// Perform health check
if err := nsp.Refresh(); err != nil {
log.Fatal(err)
}
// During normal operations, resolver weight reductions (demotions) will not be logged,
// but suspensions (removals from pool) and reinstatements (additions back) will still
// be logged for visibility into critical pool state changes.
fmt.Println("Quiet mode enabled - only critical state changes will be logged")
Output: Quiet mode enabled - only critical state changes will be logged
func (*Pool) SetRefreshPostHook ¶ added in v2.0.3
func (p *Pool) SetRefreshPostHook(fn RefreshPostHook)
SetRefreshPostHook sets the function that will be called after each Refresh() operation completes, regardless of success or failure. Pass nil to disable the post-hook.
Example ¶
ExamplePool_SetRefreshPostHook demonstrates using a post-refresh hook for logging.
nsp := nspool.NewFromPoolSlice([]string{"1.1.1.1:53", "8.8.8.8:53"})
nsp.SetHealthDomainSuffix("example.com")
// Log after refresh
nsp.SetRefreshPostHook(func(p *nspool.Pool) {
log.Printf("Refresh complete: %d available, %d unavailable",
p.AvailableCount(), p.UnavailableCount())
})
if err := nsp.Refresh(); err != nil {
log.Fatal(err)
}
func (*Pool) SetRefreshPreHook ¶ added in v2.0.3
func (p *Pool) SetRefreshPreHook(fn RefreshPreHook)
SetRefreshPreHook sets the function that will be called before each Refresh() operation. If the hook returns false, the refresh will be aborted and Refresh() will return ErrRefreshAbortedByPreHook. Pass nil to disable the pre-hook.
Example ¶
ExamplePool_SetRefreshPreHook demonstrates using a pre-refresh hook for logging.
nsp := nspool.NewFromPoolSlice([]string{"1.1.1.1:53", "8.8.8.8:53"})
nsp.SetHealthDomainSuffix("example.com")
// Log before refresh
nsp.SetRefreshPreHook(func(p *nspool.Pool) bool {
log.Printf("Starting refresh with %d resolvers",
p.AvailableCount()+p.UnavailableCount())
return true
})
if err := nsp.Refresh(); err != nil {
log.Fatal(err)
}
Example (Conditional) ¶
ExamplePool_SetRefreshPreHook_conditional demonstrates conditional refresh using pre-hook.
nsp := nspool.NewFromPoolSlice([]string{"1.1.1.1:53"})
nsp.SetHealthDomainSuffix("example.com")
// Only allow refresh during off-peak hours
nsp.SetRefreshPreHook(func(p *nspool.Pool) bool {
hour := time.Now().Hour()
if hour >= 8 && hour <= 18 {
log.Println("Skipping refresh during peak hours")
return false
}
return true
})
err := nsp.Refresh()
if err == nspool.ErrRefreshAbortedByPreHook {
log.Println("Refresh was skipped by policy")
}
func (*Pool) SetResolverCooldownPeriod ¶ added in v2.0.4
SetResolverCooldownPeriod sets the time period after which a disabled resolver can be re-enabled. Set to 0 to disable cooldown (resolvers stay disabled). Default is 1 hour.
func (*Pool) SetResolverDisableThreshold ¶ added in v2.0.4
SetResolverDisableThreshold sets the error rate threshold at which a resolver is completely disabled. Set to 0 to disable this behavior. Default is 0.20 (20%).
func (*Pool) SetResolverErrorThreshold ¶ added in v2.0.4
SetResolverErrorThreshold sets the error rate threshold at which a resolver's weight begins to be reduced. Set to 0 to disable this behavior. Default is 0.05 (5%).
func (*Pool) StopSignalHandler ¶ added in v2.0.4
func (p *Pool) StopSignalHandler()
StopSignalHandler stops the currently running signal handler goroutine if one is active. If no signal handler is running, this method does nothing. This is useful for cleaning up resources when the signal handler is no longer needed, or before installing a new handler.
func (*Pool) UnavailableCount ¶
UnavailableCount returns the number of currently unavailable resolvers.
func (*Pool) UnavailableResolvers ¶
UnavailableResolvers returns a copy of the list of currently unavailable resolvers. The returned slice can be safely modified without affecting the pool's internal state. Returns nil if the pool is nil.
type RefreshPostHook ¶ added in v2.0.3
type RefreshPostHook func(*Pool)
RefreshPostHook is the signature for a function called after Refresh() completes. It receives a pointer to the Pool that was just refreshed. This hook has no return value and is called regardless of whether the refresh succeeded or failed. It can be used to log results, update metrics, or trigger other actions based on the refresh outcome.
type RefreshPreHook ¶ added in v2.0.3
RefreshPreHook is the signature for a function called before Refresh() starts. It receives a pointer to the Pool being refreshed and must return a boolean. If it returns false, the Refresh() operation is aborted and Refresh() returns an error. This hook can be used to implement conditions under which refresh should not proceed, or to log/track refresh attempts.
type ResolverMetrics ¶ added in v2.0.4
type ResolverMetrics struct {
// contains filtered or unexported fields
}
ResolverMetrics tracks performance statistics for a single resolver.