Each operation limit ends in Timeout and names its operation. Telegram
file lookup, image download, and typing have separate names from message
sends. All wait values stay the same, including the server wait for
updates and the memory build wait.
14 files changed:
// buildLineBytes is the most bytes of one line in a build input or usage log.
const buildLineBytes = 1 << 20
// buildLineBytes is the most bytes of one line in a build input or usage log.
const buildLineBytes = 1 << 20
+// buildWaitTimeout is the longest wait for pending memory builds.
+const buildWaitTimeout = time.Second
+
// buildQuotaLimit is the largest increase in used quota points of a run.
const buildQuotaLimit = 15.0
// buildQuotaLimit is the largest increase in used quota points of a run.
const buildQuotaLimit = 15.0
// waitBuilds waits up to one second without leaving a child context open.
func (r *BuildRun) waitBuilds(ctx context.Context) error {
// waitBuilds waits up to one second without leaving a child context open.
func (r *BuildRun) waitBuilds(ctx context.Context) error {
- ctx, cancel := context.WithTimeout(ctx, time.Second)
+ ctx, cancel := context.WithTimeout(ctx, buildWaitTimeout)
defer cancel()
return r.memory.Wait(ctx)
defer cancel()
return r.memory.Wait(ctx)
// scheduleSource is the source of the work events of the runs.
scheduleSource = "schedule"
// scheduleSource is the source of the work events of the runs.
scheduleSource = "schedule"
- // scheduleCheck is the longest wait of Run before it looks at the times
- // again, so that it sees a suspend of the machine or a change of the
- // clock.
- scheduleCheck = time.Minute
+ // scheduleClockWaitTimeout is the longest wait of Run before it looks
+ // at the times again, so that it sees a suspend of the machine or a
+ // change of the clock.
+ scheduleClockWaitTimeout = time.Minute
// scheduleLate is how long after its time a run is late.
scheduleLate = time.Minute
// scheduleLate is how long after its time a run is late.
scheduleLate = time.Minute
}
// Run starts the runs of the due schedules in l until ctx ends. It waits until
}
// Run starts the runs of the due schedules in l until ctx ends. It waits until
-// the first due time, at most scheduleCheck at a time, and also wakes at a set
-// or a remove. So a schedule that came due while the daemon was stopped runs at
-// the start. It returns the error of a write of the log or of the file.
+// the first due time, at most scheduleClockWaitTimeout at a time, and also
+// wakes at a set or a remove. So a schedule that came due while the daemon was
+// stopped runs at the start. It returns the error of a write of the log or of
+// the file.
func (s *Schedules) Run(ctx context.Context, l *TurnLoop) error {
for {
err := s.deliver(ctx, l)
func (s *Schedules) Run(ctx context.Context, l *TurnLoop) error {
for {
err := s.deliver(ctx, l)
wait, found := s.Wait(s.clock())
if found {
wait, found := s.Wait(s.clock())
if found {
- timer = time.NewTimer(min(wait, scheduleCheck))
+ timer = time.NewTimer(min(wait, scheduleClockWaitTimeout))
synctest.Wait()
require.Zero(t, loop.memory.Len())
clock.Set(clock.Now().Add(5 * time.Minute))
synctest.Wait()
require.Zero(t, loop.memory.Len())
clock.Set(clock.Now().Add(5 * time.Minute))
- time.Sleep(scheduleCheck)
+ time.Sleep(scheduleClockWaitTimeout)
synctest.Wait()
require.Equal(t, 1, loop.memory.Len())
require.Contains(t, events.Last("work"), "Check the clock.")
synctest.Wait()
require.Equal(t, 1, loop.memory.Len())
require.Contains(t, events.Last("work"), "Check the clock.")
- // telegramPollSeconds is how long one getUpdates call waits for an
- // update.
- telegramPollSeconds = 50
+ // telegramUpdateWaitTimeout is how long one getUpdates call waits for
+ // an update.
+ telegramUpdateWaitTimeout = 50 * time.Second
- // telegramPollSlack is how much longer than telegramPollSeconds a
+ // telegramPollSlack is how much longer than telegramUpdateWaitTimeout a
// getUpdates call can take before the bot gives it up.
telegramPollSlack = 20 * time.Second
// telegramPollTimeout is how long one getUpdates call can take.
// getUpdates call can take before the bot gives it up.
telegramPollSlack = 20 * time.Second
// telegramPollTimeout is how long one getUpdates call can take.
- telegramPollTimeout = telegramPollSeconds*time.Second + telegramPollSlack
-
- // telegramSendTimeout is how long a sendMessage, sendRichMessage, or
- // sendChatAction call can take. A connection that stops without a
- // close, such as after a network change, then fails the call, and the
- // sender tries again, instead of a wait until TCP gives up. The client
- // has no timeout of its own, because the long poll of getUpdates needs
- // a longer limit.
+ telegramPollTimeout = telegramUpdateWaitTimeout + telegramPollSlack
+
+ // telegramSendTimeout is how long a sendMessage or sendRichMessage call
+ // can take. A connection that stops without a close, such as after a
+ // network change, then fails the call, and the sender tries again,
+ // instead of a wait until TCP gives up. The client has no timeout of
+ // its own, because the long poll of getUpdates needs a longer limit.
telegramSendTimeout = 30 * time.Second
telegramSendTimeout = 30 * time.Second
+ // telegramFileLookupTimeout is the longest wait for image file details.
+ telegramFileLookupTimeout = 30 * time.Second
+
+ // telegramImageDownloadTimeout is the longest wait for image bytes.
+ telegramImageDownloadTimeout = 30 * time.Second
+
+ // telegramTypingTimeout is the longest wait to show the typing action.
+ telegramTypingTimeout = 30 * time.Second
+
// telegramAnswerBytes is the most bytes of one answer of the Bot API.
telegramAnswerBytes = 16 << 20
)
// telegramAnswerBytes is the most bytes of one answer of the Bot API.
telegramAnswerBytes = 16 << 20
)
-// GetUpdates waits for the updates from offset on, up to telegramPollSeconds,
-// and returns them. Telegram forgets each update before offset. Only new
-// messages are asked for.
+// GetUpdates waits for the updates from offset on, up to
+// telegramUpdateWaitTimeout, and returns them. Telegram forgets each update
+// before offset. Only new messages are asked for.
func (b *TelegramAPI) GetUpdates(ctx context.Context, offset int64) ([]TelegramUpdate, error) {
var updates []TelegramUpdate
err := b.call(ctx, telegramPollTimeout, "getUpdates", map[string]any{
"offset": offset,
func (b *TelegramAPI) GetUpdates(ctx context.Context, offset int64) ([]TelegramUpdate, error) {
var updates []TelegramUpdate
err := b.call(ctx, telegramPollTimeout, "getUpdates", map[string]any{
"offset": offset,
- "timeout": telegramPollSeconds,
+ "timeout": int(telegramUpdateWaitTimeout / time.Second),
"allowed_updates": []string{"message"},
}, &updates)
"allowed_updates": []string{"message"},
}, &updates)
Size int64 `json:"file_size"`
}
Size int64 `json:"file_size"`
}
- err = b.call(ctx, telegramSendTimeout, "getFile", map[string]any{"file_id": id}, &file)
+ err = b.call(ctx, telegramFileLookupTimeout, "getFile", map[string]any{"file_id": id}, &file)
if err != nil {
return nil, fmt.Errorf("get image file: %w", err)
}
if err != nil {
return nil, fmt.Errorf("get image file: %w", err)
}
return nil, errors.New("invalid image file path")
}
return nil, errors.New("invalid image file path")
}
- ctx, cancel := context.WithTimeout(ctx, telegramSendTimeout)
+ ctx, cancel := context.WithTimeout(ctx, telegramImageDownloadTimeout)
defer cancel()
request, err := http.NewRequestWithContext(ctx, http.MethodGet, b.base+"/file/bot"+b.token+"/"+file.Path, nil)
defer cancel()
request, err := http.NewRequestWithContext(ctx, http.MethodGet, b.base+"/file/bot"+b.token+"/"+file.Path, nil)
response, err := b.http.Do(request)
if err != nil {
response, err := b.http.Do(request)
if err != nil {
- return nil, b.networkError("image download failed", err, telegramSendTimeout)
+ return nil, b.networkError("image download failed", err, telegramImageDownloadTimeout)
}
defer func() {
closeErr := response.Body.Close()
if closeErr != nil {
}
defer func() {
closeErr := response.Body.Close()
if closeErr != nil {
- err = errors.Join(err, b.networkError("close image download", closeErr, telegramSendTimeout))
+ err = errors.Join(err, b.networkError("close image download", closeErr, telegramImageDownloadTimeout))
data, err = io.ReadAll(io.LimitReader(response.Body, imageMaxBytes+1))
if err != nil {
data, err = io.ReadAll(io.LimitReader(response.Body, imageMaxBytes+1))
if err != nil {
- return nil, b.networkError("image cut off", err, telegramSendTimeout)
+ return nil, b.networkError("image cut off", err, telegramImageDownloadTimeout)
}
if len(data) > imageMaxBytes {
}
if len(data) > imageMaxBytes {
}
// SendTyping shows the typing action in chat for about five seconds. A call
}
// SendTyping shows the typing action in chat for about five seconds. A call
-// that takes longer than telegramSendTimeout fails with a TelegramNetworkError.
+// that takes longer than telegramTypingTimeout fails with a
+// TelegramNetworkError.
func (b *TelegramAPI) SendTyping(ctx context.Context, chat int64) error {
func (b *TelegramAPI) SendTyping(ctx context.Context, chat int64) error {
- return b.call(ctx, telegramSendTimeout, "sendChatAction", map[string]any{
+ return b.call(ctx, telegramTypingTimeout, "sendChatAction", map[string]any{
"chat_id": chat,
"action": "typing",
}, nil)
"chat_id": chat,
"action": "typing",
}, nil)
require.Equal(t, "getUpdates", call.method)
require.Equal(t, map[string]any{
"offset": float64(7),
require.Equal(t, "getUpdates", call.method)
require.Equal(t, map[string]any{
"offset": float64(7),
- "timeout": float64(telegramPollSeconds),
+ "timeout": float64(telegramUpdateWaitTimeout / time.Second),
"allowed_updates": []any{"message"},
}, call.params)
}
"allowed_updates": []any{"message"},
}, call.params)
}
// output, enough for toolClipCharacters/2 characters of 4 bytes.
toolClipBytes = 4 * toolClipCharacters / 2
// output, enough for toolClipCharacters/2 characters of 4 bytes.
toolClipBytes = 4 * toolClipCharacters / 2
- // toolShellWaitDelay is how long a command can keep its output open
+ // toolShellOutputTimeout is how long a command can keep its output open
// after it ends or after its kill.
// after it ends or after its kill.
- toolShellWaitDelay = 2 * time.Second
+ toolShellOutputTimeout = 2 * time.Second
)
// ToolLog is the log that the tools write their calls and results to.
)
// ToolLog is the log that the tools write their calls and results to.
cmd.Cancel = func() error {
return syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
}
cmd.Cancel = func() error {
return syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
}
- cmd.WaitDelay = toolShellWaitDelay
+ cmd.WaitDelay = toolShellOutputTimeout
output := &ToolHeadTail{}
cmd.Stdout = output
output := &ToolHeadTail{}
cmd.Stdout = output
// whatsappTimeLayout is the layout of the times in the answers.
whatsappTimeLayout = "2006-01-02 15:04"
// whatsappTimeLayout is the layout of the times in the answers.
whatsappTimeLayout = "2006-01-02 15:04"
- // whatsappPairTime is the longest time of a pairing. The library closes
- // the pairing connection after about 160 seconds.
- whatsappPairTime = 3 * time.Minute
+ // whatsappPairTimeout is the longest time of a pairing. The library
+ // closes the pairing connection after about 160 seconds.
+ whatsappPairTimeout = 3 * time.Minute
- // whatsappLogoutTime is the longest time of the logout call of an
+ // whatsappLogoutTimeout is the longest time of the logout call of an
- whatsappLogoutTime = 30 * time.Second
+ whatsappLogoutTimeout = 30 * time.Second
- // whatsappNoticeDelay is how long a disconnection lasts before the user
- // gets a notice.
- whatsappNoticeDelay = 10 * time.Minute
+ // whatsappOutageNoticeDelay is the delay from a disconnection to its
+ // notice to the user.
+ whatsappOutageNoticeDelay = 10 * time.Minute
// whatsappRetryDelay is the first wait after a failed starting
// connection.
// whatsappRetryDelay is the first wait after a failed starting
// connection.
case w.isLinked():
request.answer("WhatsApp is linked already. Run /whatsapp unlink first.")
default:
case w.isLinked():
request.answer("WhatsApp is linked already. Run /whatsapp unlink first.")
default:
- pairCtx, cancelPair := context.WithTimeout(ctx, whatsappPairTime)
+ pairCtx, cancelPair := context.WithTimeout(ctx, whatsappPairTimeout)
cancel = cancelPair
pairing.Go(func() {
defer cancelPair()
cancel = cancelPair
pairing.Go(func() {
defer cancelPair()
w.disconnectedAt = w.clock()
w.disconnections++
disconnections := w.disconnections
w.disconnectedAt = w.clock()
w.disconnections++
disconnections := w.disconnections
- w.timer = time.AfterFunc(whatsappNoticeDelay, func() {
+ w.timer = time.AfterFunc(whatsappOutageNoticeDelay, func() {
w.disconnectedLong(disconnections)
})
}
w.disconnectedLong(disconnections)
})
}
var logoutErr error
if client != nil {
var logoutErr error
if client != nil {
- ctx, cancel := context.WithTimeout(ctx, whatsappLogoutTime)
+ ctx, cancel := context.WithTimeout(ctx, whatsappLogoutTimeout)
defer cancel()
logoutErr = client.Logout(ctx)
defer cancel()
logoutErr = client.Logout(ctx)
// handle takes one event of the library and tells if it was handled. A message
// goes to the inbox. The names of the groups follow the events of the groups. A
// connection starts a catch-up of the inbox, which ends at OfflineSyncCompleted
// handle takes one event of the library and tells if it was handled. A message
// goes to the inbox. The names of the groups follow the events of the groups. A
// connection starts a catch-up of the inbox, which ends at OfflineSyncCompleted
-// or after whatsappCatchupLimit. A disconnection keeps the time of its start
-// while Run or the library tries again. After whatsappNoticeDelay of a
+// or after whatsappCatchupTimeout. A disconnection keeps the time of its start
+// while Run or the library tries again. After whatsappOutageNoticeDelay of a
// disconnection, all clients get one notice, and they get one more when the
// connection comes back. A disconnection that the library does not try again
// gives a notice at once.
// disconnection, all clients get one notice, and they get one more when the
// connection comes back. A disconnection that the library does not try again
// gives a notice at once.
- // whatsappGroupsLookupTime is the longest time of a read of group
+ // whatsappGroupLookupTimeout is the longest time of a read of group
- whatsappGroupsLookupTime = 10 * time.Second
+ whatsappGroupLookupTimeout = 10 * time.Second
// whatsappGroupsRefresh is the shortest time between two reads of the
// groups from WhatsApp for a group with no name.
// whatsappGroupsRefresh is the shortest time between two reads of the
// groups from WhatsApp for a group with no name.
- ctx, cancel := context.WithTimeout(ctx, whatsappGroupsLookupTime)
+ ctx, cancel := context.WithTimeout(ctx, whatsappGroupLookupTimeout)
defer cancel()
groups, err := link.client.GetJoinedGroups(ctx)
defer cancel()
groups, err := link.client.GetJoinedGroups(ctx)
synctest.Test(t, func(t *testing.T) {
whatsapp, fake := whatsappStartTestLinked(t)
whatsapp.client = fake
synctest.Test(t, func(t *testing.T) {
whatsapp, fake := whatsappStartTestLinked(t)
whatsapp.client = fake
- fake.downloadWait = whatsappLookupTime + time.Second
+ fake.downloadWait = whatsappContactLookupTimeout + time.Second
data := imageTestPNG(t, 3, 2)
fake.downloadData = data
data := imageTestPNG(t, 3, 2)
fake.downloadData = data
- // whatsappLookupTime is the longest time of a read of names in the
- // session.
- whatsappLookupTime = 10 * time.Second
+ // whatsappContactLookupTimeout is the longest time of a read of names
+ // in the session.
+ whatsappContactLookupTimeout = 10 * time.Second
- // whatsappImageTime is the longest time of an image download.
- whatsappImageTime = 2 * time.Minute
+ // whatsappImageDownloadTimeout is the longest time of an image
+ // download.
+ whatsappImageDownloadTimeout = 2 * time.Minute
// whatsappSource is the source of the work events of the batches.
whatsappSource = "whatsapp"
// whatsappSource is the source of the work events of the batches.
whatsappSource = "whatsapp"
- // whatsappCatchupLimit is the longest wait for the end of the catch-up
- // after a connection.
- whatsappCatchupLimit = time.Minute
+ // whatsappCatchupTimeout is the longest wait for the end of the
+ // catch-up after a connection.
+ whatsappCatchupTimeout = time.Minute
)
// newWhatsAppInbox returns the inbox of the batches in state, with clock for
)
// newWhatsAppInbox returns the inbox of the batches in state, with clock for
//
// After each connection, the servers send the messages that came while the
// daemon was away, and then OfflineSyncCompleted. Until then, or until
//
// After each connection, the servers send the messages that came while the
// daemon was away, and then OfflineSyncCompleted. Until then, or until
-// whatsappCatchupLimit passes, the closed batches wait in the state file. At
+// whatsappCatchupTimeout passes, the closed batches wait in the state file. At
// the end of the catch-up, deliver closes all batches and logs them. It wakes
// the root once for its batches, so their catch-up gives one turn, not one for
// each chat. The batches of the state file at the start wait for the first
// the end of the catch-up, deliver closes all batches and logs them. It wakes
// the root once for its batches, so their catch-up gives one turn, not one for
// each chat. The batches of the state file at the start wait for the first
}
// startCatchup starts the catch-up of a new connection, which ends at
}
// startCatchup starts the catch-up of a new connection, which ends at
-// endCatchup or after whatsappCatchupLimit.
+// endCatchup or after whatsappCatchupTimeout.
func (i *WhatsAppInbox) startCatchup() {
i.mutex.Lock()
defer i.mutex.Unlock()
func (i *WhatsAppInbox) startCatchup() {
i.mutex.Lock()
defer i.mutex.Unlock()
- i.catchupTimer = time.AfterFunc(whatsappCatchupLimit, func() {
+ i.catchupTimer = time.AfterFunc(whatsappCatchupTimeout, func() {
i.caughtUpBy(catchups)
})
}
i.caughtUpBy(catchups)
})
}
// daemon. An image that cannot be downloaded or stored gets a text marker. A
// message that the batches do not take is handled with nothing to do.
func (i *WhatsAppInbox) receive(ctx context.Context, link WhatsAppLink, event *events.Message) bool {
// daemon. An image that cannot be downloaded or stored gets a text marker. A
// message that the batches do not take is handled with nothing to do.
func (i *WhatsAppInbox) receive(ctx context.Context, link WhatsAppLink, event *events.Message) bool {
- lookupCtx, cancel := context.WithTimeout(ctx, whatsappLookupTime)
+ lookupCtx, cancel := context.WithTimeout(ctx, whatsappContactLookupTimeout)
defer cancel()
chat, message, found := whatsappMessage(lookupCtx, link.device, link.own, event)
defer cancel()
chat, message, found := whatsappMessage(lookupCtx, link.device, link.own, event)
}
if event.Message.GetImageMessage() != nil {
}
if event.Message.GetImageMessage() != nil {
- ctx, cancel := context.WithTimeout(ctx, whatsappImageTime)
+ ctx, cancel := context.WithTimeout(ctx, whatsappImageDownloadTimeout)
defer cancel()
message.Text = i.imageText(ctx, link, event, message.Text)
defer cancel()
message.Text = i.imageText(ctx, link, event, message.Text)
synctest.Wait()
require.True(t, test.fake.Emit(whatsappTestMessage(whatsappTestAna, whatsappTestOwn, "m1", "On my way.", time.Now())))
synctest.Wait()
synctest.Wait()
require.True(t, test.fake.Emit(whatsappTestMessage(whatsappTestAna, whatsappTestOwn, "m1", "On my way.", time.Now())))
synctest.Wait()
- time.Sleep(whatsappBatchQuiet - time.Nanosecond)
+ time.Sleep(whatsappBatchIdleTimeout - time.Nanosecond)
synctest.Wait()
require.Zero(t, test.loop.memory.Len())
synctest.Wait()
require.Zero(t, test.loop.memory.Len())
require.NoError(t, test.whatsapp.inbox.deliver(t.Context(), test.loop, test.whatsapp.link(), false))
require.Zero(t, test.loop.memory.Len())
require.NoError(t, test.whatsapp.inbox.deliver(t.Context(), test.loop, test.whatsapp.link(), false))
require.Zero(t, test.loop.memory.Len())
- time.Sleep(whatsappCatchupLimit)
+ time.Sleep(whatsappCatchupTimeout)
synctest.Wait()
require.NoError(t, test.whatsapp.inbox.deliver(t.Context(), test.loop, test.whatsapp.link(), false))
require.Equal(t, 1, test.loop.memory.Len())
synctest.Wait()
require.NoError(t, test.whatsapp.inbox.deliver(t.Context(), test.loop, test.whatsapp.link(), false))
require.Equal(t, 1, test.loop.memory.Len())
- // whatsappSendTime is the longest time of a send.
- whatsappSendTime = 30 * time.Second
+ // whatsappSendTimeout is the longest time of a send.
+ whatsappSendTimeout = 30 * time.Second
// whatsappSendBytes is the most bytes of the text of a send.
whatsappSendBytes = 65536
// whatsappSendBytes is the most bytes of the text of a send.
whatsappSendBytes = 65536
- sendCtx, cancel := context.WithTimeout(ctx, whatsappSendTime)
+ sendCtx, cancel := context.WithTimeout(ctx, whatsappSendTimeout)
defer cancel()
response, err := link.client.SendMessage(sendCtx, jid, &waE2E.Message{
defer cancel()
response, err := link.client.SendMessage(sendCtx, jid, &waE2E.Message{
// the batches that are not in the log yet and the records of the sends.
whatsappStateFileName = "state.json"
// the batches that are not in the log yet and the records of the sends.
whatsappStateFileName = "state.json"
- // whatsappBatchQuiet is how long a chat is quiet before its batch
+ // whatsappBatchIdleTimeout is how long a chat is quiet before its batch
- whatsappBatchQuiet = 20 * time.Second
+ whatsappBatchIdleTimeout = 20 * time.Second
- // whatsappBatchWindow is the longest time of a batch.
- whatsappBatchWindow = 2 * time.Minute
+ // whatsappBatchTimeout is the longest time of a batch.
+ whatsappBatchTimeout = 2 * time.Minute
// whatsappBatchMessages is the most messages of a batch.
whatsappBatchMessages = 50
// whatsappBatchMessages is the most messages of a batch.
whatsappBatchMessages = 50
)
// openWhatsAppState reads the batches and the send records of the state file at
)
// openWhatsAppState reads the batches and the send records of the state file at
-// path. A missing file holds none. A batch closes after whatsappBatchQuiet with
-// no message, or after whatsappBatchWindow at the latest.
+// path. A missing file holds none. A batch closes after
+// whatsappBatchIdleTimeout with no message, or after whatsappBatchTimeout at
+// the latest.
func openWhatsAppState(path string) (*WhatsAppState, error) {
s := &WhatsAppState{
path: path,
func openWhatsAppState(path string) (*WhatsAppState, error) {
s := &WhatsAppState{
path: path,
// WhatsAppState holds the state file: the send records, and the batches of the
// WhatsApp messages that are not in the log yet, open and closed, in the order
// of their first message. The messages of one chat form one batch while the
// WhatsAppState holds the state file: the send records, and the batches of the
// WhatsApp messages that are not in the log yet, open and closed, in the order
// of their first message. The messages of one chat form one batch while the
-// times of the messages are at most whatsappBatchQuiet apart, at most
-// whatsappBatchWindow after the first, and the batch has fewer than
+// times of the messages are at most whatsappBatchIdleTimeout apart, at most
+// whatsappBatchTimeout after the first, and the batch has fewer than
// whatsappBatchMessages messages. The times are the WhatsApp times, so a
// catch-up after a stop gives the same batches as live messages. A batch also
// whatsappBatchMessages messages. The times are the WhatsApp times, so a
// catch-up after a stop gives the same batches as live messages. A batch also
-// closes when whatsappBatchQuiet passes after the arrival of its last message,
-// or whatsappBatchWindow after the arrival of its first message, in real time.
+// closes when whatsappBatchIdleTimeout passes after the arrival of its last
+// message, or whatsappBatchTimeout after the arrival of its first message, in
+// real time.
//
// A send record keeps the result of a send by its ID, so that a repeated call
// of the send tool does not send again. The state file keeps the last
//
// A send record keeps the result of a send by its ID, so that a repeated call
// of the send tool does not send again. The state file keeps the last
- if message.Time.Sub(batch.Messages[len(batch.Messages)-1].Time) > whatsappBatchQuiet || message.Time.Sub(batch.Messages[0].Time) > whatsappBatchWindow {
+ if message.Time.Sub(batch.Messages[len(batch.Messages)-1].Time) > whatsappBatchIdleTimeout || message.Time.Sub(batch.Messages[0].Time) > whatsappBatchTimeout {
batch.Closed = true
closed = true
index = -1
batch.Closed = true
closed = true
index = -1
// deadline returns when batch closes in real time.
func (s *WhatsAppState) deadline(batch WhatsAppBatch) time.Time {
// deadline returns when batch closes in real time.
func (s *WhatsAppState) deadline(batch WhatsAppBatch) time.Time {
- quiet := batch.Last.Add(whatsappBatchQuiet)
- window := batch.First.Add(whatsappBatchWindow)
+ quiet := batch.Last.Add(whatsappBatchIdleTimeout)
+ window := batch.First.Add(whatsappBatchTimeout)
if window.Before(quiet) {
return window
}
if window.Before(quiet) {
return window
}
since := time.Now().Format(whatsappTimeLayout)
since := time.Now().Format(whatsappTimeLayout)
- time.Sleep(whatsappNoticeDelay)
+ time.Sleep(whatsappOutageNoticeDelay)
synctest.Wait()
require.Equal(t, 1, test.events.Count("notice"))
require.Equal(t, "WhatsApp is disconnected since "+since+". OneChat tries again.", test.events.Last("notice"))
synctest.Wait()
require.Equal(t, 1, test.events.Count("notice"))
require.Equal(t, "WhatsApp is disconnected since "+since+". OneChat tries again.", test.events.Last("notice"))
- time.Sleep(whatsappNoticeDelay)
+ time.Sleep(whatsappOutageNoticeDelay)
synctest.Wait()
require.Equal(t, 1, test.events.Count("notice"))
test.fake.mutex.Lock()
synctest.Wait()
require.Equal(t, 1, test.events.Count("notice"))
test.fake.mutex.Lock()
require.True(t, test.fake.Emit(&events.Connected{}))
require.True(t, test.fake.Emit(&events.Disconnected{}))
require.True(t, test.fake.Emit(&events.Connected{}))
require.True(t, test.fake.Emit(&events.Connected{}))
require.True(t, test.fake.Emit(&events.Disconnected{}))
require.True(t, test.fake.Emit(&events.Connected{}))
- time.Sleep(whatsappNoticeDelay + time.Second)
+ time.Sleep(whatsappOutageNoticeDelay + time.Second)
synctest.Wait()
require.Zero(t, test.events.Count("notice"))
require.True(t, test.fake.Emit(&events.Disconnected{}))
require.True(t, test.fake.Emit(&events.Disconnected{}))
synctest.Wait()
require.Zero(t, test.events.Count("notice"))
require.True(t, test.fake.Emit(&events.Disconnected{}))
require.True(t, test.fake.Emit(&events.Disconnected{}))
- time.Sleep(whatsappNoticeDelay)
+ time.Sleep(whatsappOutageNoticeDelay)
synctest.Wait()
require.Equal(t, 1, test.events.Count("notice"))
require.Contains(t, test.events.Last("notice"), "OneChat tries again.")
require.True(t, test.fake.Emit(&events.Disconnected{}))
synctest.Wait()
require.Equal(t, 1, test.events.Count("notice"))
require.Contains(t, test.events.Last("notice"), "OneChat tries again.")
require.True(t, test.fake.Emit(&events.Disconnected{}))
- time.Sleep(whatsappNoticeDelay)
+ time.Sleep(whatsappOutageNoticeDelay)
synctest.Wait()
require.Equal(t, 1, test.events.Count("notice"))
synctest.Wait()
require.Equal(t, 1, test.events.Count("notice"))