@@ -26,7 +26,9 @@ import (
2626 "gopkg.in/yaml.v3"
2727
2828 "github.com/alecthomas/units"
29+ "github.com/efficientgo/core/testutil"
2930 "github.com/go-kit/log"
31+ "github.com/go-kit/log/level"
3032 "github.com/gogo/protobuf/proto"
3133 "github.com/golang/snappy"
3234 "github.com/pkg/errors"
@@ -40,19 +42,63 @@ import (
4042 "github.com/prometheus/prometheus/storage"
4143 "github.com/prometheus/prometheus/tsdb"
4244 "github.com/stretchr/testify/require"
43-
44- "github.com/efficientgo/core/testutil "
45+ "google.golang.org/grpc/credentials/insecure"
46+ "google.golang.org/grpc/resolver "
4547
4648 "github.com/thanos-io/thanos/pkg/block/metadata"
49+ "github.com/thanos-io/thanos/pkg/component"
4750 "github.com/thanos-io/thanos/pkg/extkingpin"
4851 "github.com/thanos-io/thanos/pkg/logging"
4952 "github.com/thanos-io/thanos/pkg/runutil"
53+ grpcserver "github.com/thanos-io/thanos/pkg/server/grpc"
54+ "github.com/thanos-io/thanos/pkg/store"
5055 "github.com/thanos-io/thanos/pkg/store/labelpb"
5156 "github.com/thanos-io/thanos/pkg/store/storepb"
5257 "github.com/thanos-io/thanos/pkg/store/storepb/prompb"
5358 "github.com/thanos-io/thanos/pkg/tenancy"
5459)
5560
61+ const dnsScheme = "dns"
62+
63+ type dnsResolver struct {
64+ logger log.Logger
65+ target resolver.Target
66+ cc resolver.ClientConn
67+ addrStore map [string ][]string
68+ }
69+
70+ func (r * dnsResolver ) start () {
71+ addrStrs := r .addrStore [r .target .Endpoint ()]
72+ addrs := make ([]resolver.Address , len (addrStrs ))
73+ for i , s := range addrStrs {
74+ addrs [i ] = resolver.Address {Addr : s }
75+ }
76+ if err := r .cc .UpdateState (resolver.State {Addresses : addrs }); err != nil {
77+ level .Error (r .logger ).Log ("msg" , "failed to update state" , "err" , err )
78+ }
79+ }
80+
81+ func (* dnsResolver ) ResolveNow (_ resolver.ResolveNowOptions ) {}
82+
83+ func (* dnsResolver ) Close () {}
84+
85+ type dnsResolverBuilder struct {
86+ logger log.Logger
87+ addrStore map [string ][]string
88+ }
89+
90+ func (b * dnsResolverBuilder ) Build (target resolver.Target , cc resolver.ClientConn , opts resolver.BuildOptions ) (resolver.Resolver , error ) {
91+ r := & dnsResolver {
92+ logger : b .logger ,
93+ target : target ,
94+ cc : cc ,
95+ addrStore : b .addrStore ,
96+ }
97+ r .start ()
98+ return r , nil
99+ }
100+ func (* dnsResolverBuilder ) Scheme () string { return dnsScheme }
101+
56102type fakeTenantAppendable struct {
57103 f * fakeAppendable
58104}
@@ -191,6 +237,10 @@ func (g *fakePeersGroup) close(addr string) error {
191237 return nil
192238}
193239
240+ func (g * fakePeersGroup ) closeAll () error {
241+ return nil
242+ }
243+
194244func (g * fakePeersGroup ) getConnection (_ context.Context , addr string ) (WriteableStoreAsyncClient , error ) {
195245 c , ok := g .clients [addr ]
196246 if ! ok {
@@ -1736,50 +1786,90 @@ func TestHandlerFlippingHashrings(t *testing.T) {
17361786 wg .Wait ()
17371787}
17381788
1739- func TestPeerGroup (t * testing.T ) {
1789+ func TestIngestorRestart (t * testing.T ) {
1790+ var err error
17401791 logger := log .NewLogfmtLogger (os .Stderr )
1741- serverAddress := "http://localhost:19090"
1742- dialOpts := []grpc.DialOption {grpc .WithInsecure ()}
1743- srv := startServer (logger , serverAddress )
1744- ctx := context .TODO ()
1792+ addr1 , addr2 , addr3 := "localhost:14090" , "localhost:14091" , "localhost:14092"
1793+ ing1 , ing2 := startIngestor (logger , addr1 , 0 ), startIngestor (logger , addr2 , 0 )
1794+ defer ing1 .Shutdown (err ) // srv1 is stable and will only be closed after the test ends
1795+
1796+ clientAddr := "ingestor.com"
1797+ dnsBuilder := & dnsResolverBuilder {
1798+ logger : logger ,
1799+ addrStore : map [string ][]string {clientAddr : {addr2 }},
1800+ }
1801+ resolver .Register (dnsBuilder )
1802+ dialOpts := []grpc.DialOption {
1803+ grpc .WithTransportCredentials (insecure .NewCredentials ()),
1804+ grpc .WithResolvers (resolver .Get (dnsScheme )),
1805+ }
17451806 client := NewHandler (logger , & Options {
1746- MaxBackoff : 1 * time .Second ,
1747- DialOpts : dialOpts ,
1807+ MaxBackoff : 1 * time .Second ,
1808+ DialOpts : dialOpts ,
1809+ ReplicationFactor : 2 ,
1810+ ReceiverMode : RouterOnly ,
1811+ ForwardTimeout : 15 * time .Second ,
17481812 })
1749- _ , err := client .peers .getConnection (ctx , serverAddress )
1750- require .NoError (t , err )
1751- // close the server and wait for the backoff to kick in and see how long it takes
1752- srv .Close ()
1753- // server is closed, now we can't send requests to it
1754- er := endpointReplica {endpoint : serverAddress , replica : 0 }
1755- data := trackedSeries {
1756- timeSeries : []prompb.TimeSeries {
1813+ // one of the endpoints is DNS and wire up to different backend address on the fly
1814+ client .Hashring (& simpleHashring {addr1 , fmt .Sprintf ("%s:///%s" , dnsScheme , clientAddr )})
1815+ defer client .Close ()
1816+
1817+ ctx := context .TODO ()
1818+ data := & prompb.WriteRequest {
1819+ Timeseries : []prompb.TimeSeries {
17571820 {
1758- Labels : labelpb .ZLabelsFromPromLabels (labels .FromStrings ("foo" , "bar" )),
1821+ Labels : labelpb .ZLabelsFromPromLabels (labels .FromStrings ("foo" , addr3 )),
17591822 Samples : []prompb.Sample {{Timestamp : time .Now ().Unix (), Value : 123 }},
17601823 },
17611824 },
17621825 }
17631826
1764- N := 50
1765- responses := make (chan writeResponse , N )
1766- for i := 0 ; i < N ; i ++ {
1767- var wg sync.WaitGroup
1768- wg .Add (1 )
1769- client .sendRemoteWrite (ctx , "" , er , data , false , responses , & wg )
1770- wg .Wait ()
1771- _ , err = client .peers .getConnection (ctx , serverAddress )
1772- require .Error (t , errUnavailable , err )
1773- time .Sleep (100 * time .Millisecond )
1827+ err = client .handleRequest (ctx , 0 , "test" , data )
1828+ require .NoError (t , err )
1829+
1830+ // close srv2 to simulate ingestor down
1831+ ing2 .Shutdown (err )
1832+ ing3 := startIngestor (logger , addr3 , 2 * time .Second )
1833+ defer ing3 .Shutdown (err )
1834+ // bind the new backend to the same DNS
1835+ dnsBuilder .addrStore [clientAddr ] = []string {addr3 }
1836+
1837+ iter , errs := 10 , 0
1838+ for i := 0 ; i < iter ; i ++ {
1839+ err = client .handleRequest (ctx , 0 , "test" , data )
1840+ if err != nil {
1841+ require .Error (t , errUnavailable , err )
1842+ errs ++
1843+ } else {
1844+ break
1845+ }
1846+ time .Sleep (500 * time .Millisecond )
17741847 }
1848+ require .Greater (t , errs , 0 , "expected to have unavailable errors initially" )
1849+ require .Less (t , errs , iter , "expected to recover quickly after server restarts" )
17751850}
17761851
1777- func startServer (logger log.Logger , serverAddress string ) * Handler {
1778- srv := NewHandler (logger , & Options {
1779- ListenAddress : serverAddress ,
1780- })
1852+ type fakeStoreServer struct {
1853+ logger log.Logger
1854+ }
1855+
1856+ func (f * fakeStoreServer ) RemoteWrite (_ context.Context , in * storepb.WriteRequest ) (* storepb.WriteResponse , error ) {
1857+ level .Debug (f .logger ).Log ("msg" , "received remote write request" , "request" , in .String ())
1858+ return & storepb.WriteResponse {}, nil
1859+ }
1860+
1861+ func startIngestor (logger log.Logger , serverAddress string , delay time.Duration ) * grpcserver.Server {
1862+ h := & fakeStoreServer {logger : logger }
1863+ srv := grpcserver .TestServer (logger , component .Receive , serverAddress ,
1864+ grpcserver .WithServer (store .RegisterWritableStoreServer (h )),
1865+ )
17811866 go func () {
1782- srv .Run ()
1867+ if delay > 0 {
1868+ time .Sleep (delay )
1869+ }
1870+ if err := srv .ListenAndServe (); err != nil {
1871+ level .Error (logger ).Log ("msg" , "server error" , "addr" , serverAddress , "err" , err )
1872+ }
17831873 }()
17841874 return srv
17851875}
0 commit comments