Release v1.13.0: console polish, API log sort, R2 multipart leak fix#259
Merged
alexanderwanyoike merged 22 commits intomainfrom Apr 12, 2026
Merged
Release v1.13.0: console polish, API log sort, R2 multipart leak fix#259alexanderwanyoike merged 22 commits intomainfrom
alexanderwanyoike merged 22 commits intomainfrom
Conversation
1d loaded too many metrics for active bots. 1h provides a tighter window that loads quickly while showing recent data. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: default interval 1h for scheduled bots
The polling interval captured a stale fetchLogs closure. Using a ref ensures the interval always calls the latest version without needing to recreate the timer on every query change. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: prevent console refresh loop on interval change
…ries Both useBotLogs and useBotLogsStream had separate expansion logic that dropped the timestamp field. Extracted a shared expandLogEntries function in lib/log-utils.ts that preserves timestamp. Both hooks now import from the same source. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…-expansion fix: preserve timestamp field when expanding log entries
Users can now select polling frequency: 10s / 30s / 60s / Off. Previously hardcoded at 60s for console and 30s for dashboard. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Users can now select polling frequency: 10s / 30s / 60s / Off. Previously hardcoded at 60s for console and 30s for dashboard. Fixes from review: - Lifecycle effect depends on autoRefresh/refreshInterval - Pass refreshInterval directly (no coercion for Off) - Guard setInterval calls with refreshInterval > 0 - Accessibility: role=group, aria-label, aria-pressed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
feat: configurable refresh interval for console and dashboard
The stream hook (useBotLogsStream) hardcoded hasMore=false, so when a realtime bot switched to a date range interval its REST fetches never exposed pagination. This adds hasMore state tracking and a loadMore callback to the stream hook for its REST mode, and wires them through bot-detail-panel so the console shows "load more" for historical browsing on realtime bots. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fix: enable load more for realtime bots on non-live intervals
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
✅ Deploy Preview for the0-docs canceled.
|
- Raise MAX_LOG_ENTRIES from 2000 to 10000 so load more grows the buffer - Advance query offset after loadMore (consecutive calls work) - Add loadingMoreRef guard to prevent concurrent loadMore calls - Skip auto-refresh polling when user has paginated - Remove Virtuoso endReached auto-trigger (explicit button only) - Only auto-scroll to top when user is already at the top - Disable followOutput when not connected (no jolt on REST data) - Use ref for refreshInterval in stream hook (no SSE reconnection) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixed 1 file(s) based on 1 unresolved review comment. Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
…and-polish fix: console load more, scroll jolt, and SSE reconnection
Contributor
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Add sort=asc|desc to the logs API. Default is desc (newest-first). - tailFilteredLogs (single date) already returns newest-first; reverses for asc - streamFilteredLogs (date ranges) reads all, reverses, applies offset/limit for desc - Backward compatible: single-date path was already newest-first Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove newestFirst state, displayLogs reversal memo, auto-scroll effect, isUserAtTop/prevLogCountRef from console-interface.tsx - Add sort/onSortChange props to ConsoleInterface (API-controlled) - Send sort=desc in URL params from both hooks by default - Add updateQuery to stream hook for sort changes - Wire sort toggle through bot-detail-panel and mobile-bot-detail - followOutput now checks sort==="asc" instead of !newestFirst Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace limit: Infinity with a bounded max of offset + limit or 10000, whichever is larger. Prevents unbounded memory usage on large date ranges while still supporting pagination. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two upload paths were leaking incomplete multipart uploads whenever their sync context expired mid-operation, which bloated R2 billed storage (~70 GB phantom on bot-logs, ~8000 orphans on bot-state). Root causes: - minio-go ComposeObject never aborts on error. The AppendBotLogs compose branch drove it directly, so any UploadPartCopy/Complete failure leaked the upload ID. - minio-go PutObject streaming (unknown size) DOES defer an abort, but uses the caller's context which is already cancelled by the time the defer runs, so the abort request itself fails silently. - The 30s / 60s sync timeouts were too tight for R2 tail latency on the multipart-copy path, amplifying the leak rate. Fixes: - Own the multipart-copy flow in AppendBotLogs via a minio.Core seam and defer an abort that fires on a fresh background context, so caller cancellation cannot prevent cleanup. - Wrap UploadState's PutObject with a fresh-context RemoveIncompleteUpload on any error, closing the pipe with the error first so the tar.gz goroutine exits. - Extend the GC sweep with ListIncompleteUploads + AbortIncompleteUpload on both buckets, filtering by a 1h staleIncompleteUploadAge so no in-flight upload can be touched. - Bump injectable per-sync upload timeouts: logs 30s->120s, state 60s->180s. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…-uploads fix: stop leaking R2 multipart uploads on bot-logs and bot-state
…agination fix: simplify console pagination with API-side sort=desc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Release cut covering console/dashboard polish, an API-side log sort refactor, and a runtime fix for leaking R2 multipart uploads. Helm chart bumped to 0.8.0 / appVersion 1.13.0.
Console & dashboard
hasMore/loadMoreexposed from the stream hook in REST date-range mode. (fix: enable load more for realtime bots on non-live intervals #258, fix: console load more, scroll jolt, and SSE reconnection #260)expandLogEntriesextracted tolib/log-utils.ts. (fix: preserve timestamp field when expanding log entries #254)fetchLogsso there is no stale closure. (fix: prevent console refresh loop on interval change #257)loadMoreguard vialoadingMoreRef, offset only advances on success,setHasMoreskipped on prepend,refreshIntervallifecycle deps, andsetIntervalguarded with> 0so Off mode doesn't create zero-delay timers.API: log sort refactor (#261)
sort=asc|descparam to the logs endpoint (defaultdesc/ newest-first).followOutputsimplified toconnected && sort === "asc".Runtime: R2 multipart upload leak fix (#262)
bot-logsand ~8,000 orphaned multipart uploads onbot-state. Two upload paths were leaking incomplete multipart uploads whenever their sync context expired mid-operation, because neither path guaranteed an abort on a fresh context.AppendBotLogs: replacedminio.Client.ComposeObject(which has no abort-on-error) with an owned multipart-copy flow viaminio.Core. A deferred abort runs on a fresh background context so caller cancellation cannot prevent cleanup. Safe because the per-bot mutex serializes writes to the same daily key.UploadState: wrapsPutObject(unknown size → multipart streaming) with a fresh-contextRemoveIncompleteUploadon any error. minio-go's internal defer abort was using the already-cancelled caller context and failing silently.ListIncompleteUploads+AbortIncompleteUploadon theMinIOClientinterface;cleanupStaleIncompleteUploadssweep runs on both logs and state buckets each GC cycle, filtering by a 1hstaleIncompleteUploadAgeso no in-flight upload can be touched.30s → 120s, state60s → 180s. R2 tail latency was shredding legitimate uploads at the old values.bot-logsand 7,961 aborted onbot-state, so the billing baseline is already clean.Test plan
cd api && yarn test --no-coverage- 501 passcd frontend && yarn test --no-coverage && yarn build- 598 passgo test ./...- full repo suite green (gc, minio-logger, runtime/storage, daemon)aws s3api list-multipart-uploadson bothbot-logsandbot-statestays at zero for 24h; verifynssuhlwv2mw2cihrnnxpbqxxdaily log keeps growing through the day without gaps🤖 Generated with Claude Code