@@ -693,6 +693,133 @@ func TestBulkIndexer(t *testing.T) {
693693 }
694694 })
695695
696+ t .Run ("TooManyRequests - Fail" , func (t * testing.T ) {
697+ var (
698+ wg sync.WaitGroup
699+ numItems = 2
700+ )
701+
702+ esCfg := elasticsearch.Config {
703+ Transport : & mockTransport {
704+ RoundTripFunc : func (* http.Request ) (* http.Response , error ) {
705+ return & http.Response {
706+ StatusCode : http .StatusTooManyRequests ,
707+ Status : "429 TooManyRequests" ,
708+ Body : io .NopCloser (strings .NewReader (`{"took":1}` )),
709+ }, nil
710+ },
711+ },
712+
713+ MaxRetries : 5 ,
714+ RetryOnStatus : []int {502 , 503 , 504 , 429 },
715+ RetryBackoff : func (i int ) time.Duration {
716+ if os .Getenv ("DEBUG" ) != "" {
717+ fmt .Printf ("*** Retry #%d\n " , i )
718+ }
719+ return time .Duration (i ) * 100 * time .Millisecond
720+ },
721+ }
722+ if os .Getenv ("DEBUG" ) != "" {
723+ esCfg .Logger = & elastictransport.ColorLogger {Output : os .Stdout }
724+ }
725+ es , _ := elasticsearch .NewClient (esCfg )
726+
727+ biCfg := BulkIndexerConfig {NumWorkers : 1 , FlushBytes : 28 * 2 , Client : es }
728+ if os .Getenv ("DEBUG" ) != "" {
729+ biCfg .DebugLogger = log .New (os .Stdout , "" , 0 )
730+ }
731+
732+ bi , _ := NewBulkIndexer (biCfg )
733+
734+ biiFailureCallbacksCalled := atomic.Uint32 {}
735+ biiSuccessCallbacksCalled := atomic.Uint32 {}
736+
737+ for i := 1 ; i <= numItems ; i ++ {
738+ wg .Add (1 )
739+ go func (i int ) {
740+ defer wg .Done ()
741+ err := bi .Add (context .Background (), BulkIndexerItem {
742+ Action : "foo" ,
743+ Body : strings .NewReader (`{"title":"foo"}` ),
744+ OnFailure : func (ctx context.Context , item BulkIndexerItem , item2 BulkIndexerResponseItem , err error ) {
745+ _ = biiFailureCallbacksCalled .Add (1 )
746+ if err == nil {
747+ t .Errorf ("Unexpected nil error in BulkIndexerItem.OnFailure callback" )
748+ }
749+ },
750+ OnSuccess : func (ctx context.Context , item BulkIndexerItem , item2 BulkIndexerResponseItem ) {
751+ _ = biiSuccessCallbacksCalled .Add (1 )
752+ },
753+ })
754+ if err != nil {
755+ t .Errorf ("Unexpected error: %s" , err )
756+ return
757+ }
758+ }(i )
759+ }
760+ wg .Wait ()
761+
762+ if err := bi .Close (context .Background ()); err != nil {
763+ t .Errorf ("Unexpected error: %s" , err )
764+ }
765+
766+ // BulksIndexerItem.OnFailure() callbacks are called for all items.
767+ if biiFailureCallbacksCalled .Load () != uint32 (numItems ) {
768+ t .Errorf ("Unexpected NumFailedCallbacks: want=%d, got=%d" , numItems , biiFailureCallbacksCalled .Load ())
769+ }
770+
771+ // BulkIndexerItem.OnSuccess() callbacks are not called.
772+ if biiSuccessCallbacksCalled .Load () != 0 {
773+ t .Errorf ("Unexpected NumSuccessCallbacks: want=%d, got=%d" , 0 , biiSuccessCallbacksCalled .Load ())
774+ }
775+ })
776+
777+ t .Run ("JSON Decoder Failure" , func (t * testing.T ) {
778+ es , _ := elasticsearch .NewClient (elasticsearch.Config {Transport : & mockTransport {}})
779+
780+ biFailureCallbacksCalled := atomic.Uint32 {}
781+ bi , _ := NewBulkIndexer (BulkIndexerConfig {
782+ Client : es ,
783+ Decoder : customJSONDecoder {
784+ err : fmt .Errorf ("Custom JSON decoder error" ),
785+ },
786+ OnError : func (ctx context.Context , err error ) {
787+ _ = biFailureCallbacksCalled .Add (1 )
788+ },
789+ })
790+
791+ biiFailureCallbacksCalled := atomic.Uint32 {}
792+
793+ err := bi .Add (context .Background (), BulkIndexerItem {
794+ Action : "index" ,
795+ DocumentID : "1" ,
796+ Body : strings .NewReader (`{"title":"foo"}` ),
797+ OnFailure : func (ctx context.Context , item BulkIndexerItem , item2 BulkIndexerResponseItem , err error ) {
798+ _ = biiFailureCallbacksCalled .Add (1 )
799+ if err == nil {
800+ t .Errorf ("Unexpected nil error in BulkIndexerItem.OnFailure callback" )
801+ }
802+ },
803+ })
804+ if err != nil {
805+ t .Fatalf ("Unexpected error, got %s" , err )
806+ }
807+
808+ if err := bi .Close (context .Background ()); err != nil {
809+ t .Errorf ("Unexpected error: %s" , err )
810+ }
811+
812+ // BulksIndexerItem.OnFailure() callbacks are called only for failed items.
813+ if biiFailureCallbacksCalled .Load () != 1 {
814+ t .Errorf ("Unexpected NumFailedCallbacks: want=%d, got=%d" , 1 , biiFailureCallbacksCalled .Load ())
815+ }
816+
817+ // BulkIndexer.OnError() callbacks are called for all errors.
818+ if biFailureCallbacksCalled .Load () != 2 {
819+ t .Errorf ("Unexpected NumFailedCallbacks: want=%d, got=%d" , 2 , biFailureCallbacksCalled .Load ())
820+ }
821+ })
822+
696823 t .Run ("Custom JSON Decoder" , func (t * testing.T ) {
697824 es , _ := elasticsearch .NewClient (elasticsearch.Config {Transport : & mockTransport {}})
698825 bi , _ := NewBulkIndexer (BulkIndexerConfig {Client : es , Decoder : customJSONDecoder {}})
@@ -1080,8 +1207,13 @@ func TestBulkIndexerItem(t *testing.T) {
10801207 })
10811208}
10821209
1083- type customJSONDecoder struct {}
1210+ type customJSONDecoder struct {
1211+ err error
1212+ }
10841213
10851214func (d customJSONDecoder ) UnmarshalFromReader (r io.Reader , blk * BulkIndexerResponse ) error {
1215+ if d .err != nil {
1216+ return d .err
1217+ }
10861218 return json .NewDecoder (r ).Decode (blk )
10871219}
0 commit comments