Skip to content

Commit 2fa470e

Browse files
authored
Merge pull request #1484 from ydb-platform/fix-err-buffer
special error for detect about written messages can be delivered to the server when write error happened.
2 parents 98f75f0 + e4df39e commit 2fa470e

File tree

4 files changed

+43
-20
lines changed

4 files changed

+43
-20
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
* Added error ErrMessagesPutToInternalQueueBeforeError to topic writer
12
* Added write to topics within transactions
23

34
## v3.80.10

internal/topic/topicwriterinternal/writer_reconnector.go

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ import (
3131
)
3232

3333
var (
34-
errConnTimeout = xerrors.Wrap(errors.New("ydb: connection timeout"))
35-
errStopWriterReconnector = xerrors.Wrap(errors.New("ydb: stop writer reconnector"))
36-
errNonZeroSeqNo = xerrors.Wrap(errors.New("ydb: non zero seqno for auto set seqno mode"))
37-
errNonZeroCreatedAt = xerrors.Wrap(errors.New("ydb: non zero Message.CreatedAt and set auto fill created at option")) //nolint:lll
38-
errNoAllowedCodecs = xerrors.Wrap(errors.New("ydb: no allowed codecs for write to topic"))
39-
errLargeMessage = xerrors.Wrap(errors.New("ydb: message uncompressed size more, then limit"))
40-
PublicErrQueueIsFull = xerrors.Wrap(errors.New("ydb: queue is full"))
41-
errDiffetentTransactions = xerrors.Wrap(errors.New("ydb: internal writer has messages from different trasactions. It is internal logic error, write issue please: https://github.com/ydb-platform/ydb-go-sdk/issues/new?assignees=&labels=bug&projects=&template=01_BUG_REPORT.md&title=bug%3A+")) //nolint:lll
34+
errConnTimeout = xerrors.Wrap(errors.New("ydb: connection timeout"))
35+
errStopWriterReconnector = xerrors.Wrap(errors.New("ydb: stop writer reconnector"))
36+
errNonZeroSeqNo = xerrors.Wrap(errors.New("ydb: non zero seqno for auto set seqno mode")) //nolint:lll
37+
errNonZeroCreatedAt = xerrors.Wrap(errors.New("ydb: non zero Message.CreatedAt and set auto fill created at option")) //nolint:lll
38+
errNoAllowedCodecs = xerrors.Wrap(errors.New("ydb: no allowed codecs for write to topic"))
39+
errLargeMessage = xerrors.Wrap(errors.New("ydb: message uncompressed size more, then limit")) //nolint:lll
40+
PublicErrMessagesPutToInternalQueueBeforeError = xerrors.Wrap(errors.New("ydb: the messages was put to internal buffer before the error happened. It mean about the messages can be delivered to the server")) //nolint:lll
41+
errDiffetentTransactions = xerrors.Wrap(errors.New("ydb: internal writer has messages from different trasactions. It is internal logic error, write issue please: https://github.com/ydb-platform/ydb-go-sdk/issues/new?assignees=&labels=bug&projects=&template=01_BUG_REPORT.md&title=bug%3A+")) //nolint:lll
4242

4343
// errProducerIDNotEqualMessageGroupID is temporary
4444
// WithMessageGroupID is optional parameter because it allowed to be skipped by protocol.
@@ -209,7 +209,7 @@ func (w *WriterReconnector) start() {
209209
w.background.Start(name+", sendloop", w.connectionLoop)
210210
}
211211

212-
func (w *WriterReconnector) Write(ctx context.Context, messages []PublicMessage) error {
212+
func (w *WriterReconnector) Write(ctx context.Context, messages []PublicMessage) (resErr error) {
213213
if err := w.background.CloseReason(); err != nil {
214214
return xerrors.WithStackTrace(fmt.Errorf("ydb: writer is closed: %w", err))
215215
}
@@ -223,18 +223,16 @@ func (w *WriterReconnector) Write(ctx context.Context, messages []PublicMessage)
223223
semaphoreWeight := int64(len(messages))
224224
if semaphoreWeight > int64(w.cfg.MaxQueueLen) {
225225
return xerrors.WithStackTrace(fmt.Errorf(
226-
"ydb: add more messages, then max queue limit. max queue: %v, try to add: %v: %w",
226+
"ydb: add more messages, then max queue limit. max queue: %v, try to add: %v",
227227
w.cfg.MaxQueueLen,
228228
semaphoreWeight,
229-
PublicErrQueueIsFull,
230229
))
231230
}
232231
if err := w.semaphore.Acquire(ctx, semaphoreWeight); err != nil {
233232
return xerrors.WithStackTrace(
234-
fmt.Errorf("ydb: add new messages exceed max queue size limit. Add count: %v, max size: %v: %w",
233+
fmt.Errorf("ydb: add new messages exceed max queue size limit. Add count: %v, max size: %v",
235234
semaphoreWeight,
236235
w.cfg.MaxQueueLen,
237-
PublicErrQueueIsFull,
238236
))
239237
}
240238
defer func() {
@@ -254,10 +252,15 @@ func (w *WriterReconnector) Write(ctx context.Context, messages []PublicMessage)
254252
return err
255253
}
256254

257-
waiter, err := w.processMessagesWithLock(messagesSlice, &semaphoreWeight)
255+
waiter, err := w.addMessageToInternalQueueWithLock(messagesSlice, &semaphoreWeight)
258256
if err != nil {
259257
return err
260258
}
259+
defer func() {
260+
if resErr != nil {
261+
resErr = xerrors.Join(resErr, PublicErrMessagesPutToInternalQueueBeforeError)
262+
}
263+
}()
261264

262265
if !w.cfg.WaitServerAck {
263266
return nil
@@ -266,7 +269,7 @@ func (w *WriterReconnector) Write(ctx context.Context, messages []PublicMessage)
266269
return w.queue.Wait(ctx, waiter)
267270
}
268271

269-
func (w *WriterReconnector) processMessagesWithLock(
272+
func (w *WriterReconnector) addMessageToInternalQueueWithLock(
270273
messagesSlice []messageWithDataContent,
271274
semaphoreWeight *int64,
272275
) (MessageQueueAckWaiter, error) {

internal/topic/topicwriterinternal/writer_reconnector_test.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,9 +306,8 @@ func TestWriterReconnector_Write_QueueLimit(t *testing.T) {
306306
ctxNoQueueSpaceCancel()
307307
}()
308308
err = w.Write(ctxNoQueueSpace, newTestMessages(3))
309-
if !errors.Is(err, PublicErrQueueIsFull) {
310-
require.ErrorIs(t, err, PublicErrQueueIsFull)
311-
}
309+
require.Error(t, err)
310+
require.NotErrorIs(t, err, PublicErrMessagesPutToInternalQueueBeforeError)
312311

313312
go func() {
314313
waitStartQueueWait(1)
@@ -325,6 +324,24 @@ func TestWriterReconnector_Write_QueueLimit(t *testing.T) {
325324
})
326325
}
327326

327+
func TestMessagesPutToInternalQueueBeforeError(t *testing.T) {
328+
ctx := xtest.Context(t)
329+
w := newWriterReconnectorStopped(NewWriterReconnectorConfig(
330+
WithAutoSetSeqNo(false),
331+
WithMaxQueueLen(2),
332+
WithWaitAckOnWrite(true),
333+
))
334+
w.firstConnectionHandled.Store(true)
335+
336+
ctxCancel, cancel := context.WithCancel(ctx)
337+
go func() {
338+
<-w.queue.hasNewMessages
339+
cancel()
340+
}()
341+
err := w.Write(ctxCancel, newTestMessages(1))
342+
require.ErrorIs(t, err, PublicErrMessagesPutToInternalQueueBeforeError)
343+
}
344+
328345
func TestEnv(t *testing.T) {
329346
xtest.TestManyTimes(t, func(t testing.TB) {
330347
env := newTestEnv(t, nil)

topic/topicwriter/topicwriter.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ type (
1010
Message = topicwriterinternal.PublicMessage
1111
)
1212

13-
var ErrQueueLimitExceed = topicwriterinternal.PublicErrQueueIsFull
13+
var ErrMessagesPutToInternalQueueBeforeError = topicwriterinternal.PublicErrMessagesPutToInternalQueueBeforeError
1414

1515
// Writer represent write session to topic
1616
// It handles connection problems, reconnect to server when need and resend buffered messages
@@ -38,7 +38,9 @@ func NewWriter(writer *topicwriterinternal.WriterReconnector) *Writer {
3838
// especially when connection has problems.
3939
//
4040
// It returns ErrQueueLimitExceed (must be checked by errors.Is)
41-
// if ctx cancelled before messages put to internal buffer or try to add more messages, that can be put to queue
41+
// if ctx cancelled before messages put to internal buffer or try to add more messages, that can be put to queue.
42+
// If err != nil you can check errors.Is(err, ErrMessagesPutToInternalQueueBeforeError) for check if the messages
43+
// put to buffer before error. It means that it is messages can be delivered to the server.
4244
func (w *Writer) Write(ctx context.Context, messages ...Message) error {
4345
return w.inner.Write(ctx, messages)
4446
}

0 commit comments

Comments
 (0)