storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/event/target/store.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2019 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package target 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "strings" 24 "syscall" 25 "time" 26 27 "storj.io/minio/pkg/event" 28 ) 29 30 const retryInterval = 3 * time.Second 31 32 // errNotConnected - indicates that the target connection is not active. 33 var errNotConnected = errors.New("not connected to target server/service") 34 35 // errLimitExceeded error is sent when the maximum limit is reached. 36 var errLimitExceeded = errors.New("the maximum store limit reached") 37 38 // Store - To persist the events. 39 type Store interface { 40 Put(event event.Event) error 41 Get(key string) (event.Event, error) 42 List() ([]string, error) 43 Del(key string) error 44 Open() error 45 } 46 47 // replayEvents - Reads the events from the store and replays. 48 func replayEvents(store Store, doneCh <-chan struct{}, loggerOnce func(ctx context.Context, err error, id interface{}, kind ...interface{}), id event.TargetID) <-chan string { 49 eventKeyCh := make(chan string) 50 51 go func() { 52 retryTicker := time.NewTicker(retryInterval) 53 defer retryTicker.Stop() 54 defer close(eventKeyCh) 55 for { 56 names, err := store.List() 57 if err == nil { 58 for _, name := range names { 59 select { 60 case eventKeyCh <- strings.TrimSuffix(name, eventExt): 61 // Get next key. 62 case <-doneCh: 63 return 64 } 65 } 66 } 67 68 if len(names) < 2 { 69 select { 70 case <-retryTicker.C: 71 if err != nil { 72 loggerOnce(context.Background(), 73 fmt.Errorf("store.List() failed '%w'", err), id) 74 } 75 case <-doneCh: 76 return 77 } 78 } 79 } 80 }() 81 82 return eventKeyCh 83 } 84 85 // IsConnRefusedErr - To check fot "connection refused" error. 86 func IsConnRefusedErr(err error) bool { 87 return errors.Is(err, syscall.ECONNREFUSED) 88 } 89 90 // IsConnResetErr - Checks for connection reset errors. 91 func IsConnResetErr(err error) bool { 92 if strings.Contains(err.Error(), "connection reset by peer") { 93 return true 94 } 95 // incase if error message is wrapped. 96 return errors.Is(err, syscall.ECONNRESET) 97 } 98 99 // sendEvents - Reads events from the store and re-plays. 100 func sendEvents(target event.Target, eventKeyCh <-chan string, doneCh <-chan struct{}, loggerOnce func(ctx context.Context, err error, id interface{}, kind ...interface{})) { 101 retryTicker := time.NewTicker(retryInterval) 102 defer retryTicker.Stop() 103 104 send := func(eventKey string) bool { 105 for { 106 err := target.Send(eventKey) 107 if err == nil { 108 break 109 } 110 111 if err != errNotConnected && !IsConnResetErr(err) { 112 loggerOnce(context.Background(), 113 fmt.Errorf("target.Send() failed with '%w'", err), 114 target.ID()) 115 } 116 117 // Retrying after 3secs back-off 118 119 select { 120 case <-retryTicker.C: 121 case <-doneCh: 122 return false 123 } 124 } 125 return true 126 } 127 128 for { 129 select { 130 case eventKey, ok := <-eventKeyCh: 131 if !ok { 132 // closed channel. 133 return 134 } 135 136 if !send(eventKey) { 137 return 138 } 139 case <-doneCh: 140 return 141 } 142 } 143 }