5 回に 1 回リクエストが失われる接続で 100 回アップロードしました。失敗は 23 件から 1 件に減りました。
残る 1 件はサーバーが拒否したファイルなので、再試行では解決できません。
アップロード速度をヘッダーのファイル名の隣に表示し、キューが空のときは隠すようにしました。
取りかかります。見せられるものができたらここに書きます。
再現して原因を特定しました。修正はレビューできる状態です。
アップロードキューに指数バックオフを追加しました。失敗したチャンクは最大5回まで再試行し、進捗バーに試行回数を表示します。テストはタイムアウトと 503 のケースをカバーしています。
これまで失敗したチャンクは捨てられていました。いまはキューがバックオフポリシーに待ち時間を問い合わせて再試行を予約するので、すべての再試行が1か所を通ります。
5 回失敗するとチャンクは確定で失敗扱いになり、アップロードは明確なエラーで止まります。切れた回線で再試行が続くことはありません。
キューの変更は src/upload/queue.ts に、待ち時間の設定は src/upload/backoff.ts にあります。
キューは各チャンクの状態をディスクに書き込むようになりました。いま再起動時の処理をつないでいます。
起動時にキューが保存済みの状態を読み、未完了のチャンクだけを送るので、2 GB のファイルも最初からやり直しません。
戦略には市場に出るとあったので、そのための関数を追加しました。
1export async function goToMarket() {2await ship();3await tellDenis();4}
テストは 1 件通っています。市場からの返事はまだありません。
ウォッチャーが書き込む前にテストがファイルを読んでいました。flush イベントを待つようにしたところ、200 回連続で通っています。
1test('reads the synced file', async () => {2await writeFile(path, 'hello');3await watcher.flushed(path);4const text = await readFile(path);5expect(text).toBe('hello');6});
待機はテストヘルパーに入れたので、ほかの同期テストにも効きます。
新しいページはできました。タブを削除する前に設定の移行を実行する必要があります。
| 旧タブ | 新しいセクション |
|---|---|
| 一般 | ワークスペース |
| 外観 | ワークスペース |
| アカウント | プロフィール |
移行は 212 件の設定をエラーなく処理し、古いタブはなくなりました。設定はすべて 1 ページにあります。
ここで止めます。移行を実行するまで古いタブは残ります。
指摘が 2 つあります。セッション Cookie に有効期限がなく、ログイン後のリダイレクトが任意の URL を受け付けます。ほかは問題ありません。
完了しました。選んだ修正はそれぞれテスト付きで反映し、後回しにした分はプルリクエストにコメントとして残しました。
了解しました。何も変更せず、指摘はプルリクエストのコメントとして残します。
クリーンな環境で新しいコマンドを試し、動作を確認しました。
1bun add -g uploader2uploader --help
古い curl コマンドも動くので、代替手段として残せます。
完了しました。新しいコマンドは指定の場所に載せ、古いものは代替手段として残しました。
時間の大半は検索のたびに全ファイルを読むことに使われています。インデックスで短縮でき、小さなリポジトリはほとんど変わりません。
インデックスはファイルが変わると更新されるので、全体の再構築は不要です。
ツリーはディスクのキャッシュから読み込み、バックグラウンドで更新します。変わるのは待ち時間だけです。
- キャッシュヒット
- 94%
- ディスク上のサイズ
- 2.1 MB
- ツリーの読み込み時間
- 40 ms
ブランチが変わるとキャッシュは自動で消えます。
見つけました。空のファイルは null になり、コードがすぐそのフィールドを読んでいます。
1export function loadConfig(path: string) {2const text = readFileSync(path, 'utf8');3if (text.trim() === '') return defaults;4return { ...defaults, ...parse(text) };5}
いまは空のファイルを既定の設定として扱い、壊れたファイルには明確なエラーを出します。
新しい issue は 5 件です。3 件は本物のバグで、そのうち 1 件は次のリリースまで待てます。
| Issue | 種類 |
|---|---|
| Upload stalls at 99% on Safari | bug |
| Crash on a file named final_final_v2_🦆.mov | bug |
| Progress bar jumps back after resume | bug |
| Drag a folder into the upload list | feature |
| Is there a size limit? Asking for a 400 GB log file | question |
すべてにラベルを付け、重複は古い報告にリンクしました。
uploaderで何に取り組みますか?
失敗したアップロードの再試行
アップロードキューに指数バックオフを追加しました。失敗したチャンクは最大5回まで再試行し、進捗バーに試行回数を表示します。テストはタイムアウトと 503 のケースをカバーしています。
これまで失敗したチャンクは捨てられていました。いまはキューがバックオフポリシーに待ち時間を問い合わせて再試行を予約するので、すべての再試行が1か所を通ります。
const result = await sendChunk(chunk); if (!result.ok) return fail(chunk); if (!result.ok) { const delay = backoff.next(chunk.attempt); if (delay === null) return fail(chunk); return schedule(chunk, delay); } progress.advance(chunk.size); const DELAYS = [500, 1000, 2000, 4000, 8000]; export const backoff = { next(attempt: number) { return DELAYS[attempt] ?? null; } }; 1import { backoff } from './backoff';2import { sendChunk } from './client';3import { progress } from './progress';4import type { Chunk, UploadResult } from './types';56// TODO: remove before launch (added in 2023)7const MAX_PARALLEL = 4;8const queue: Chunk[] = [];9let running = 0;1011export function enqueue(chunks: Chunk[]) {12queue.push(...chunks);13void drain();14}1516async function drain() {17while (running < MAX_PARALLEL && queue.length > 0) {18const chunk = queue.shift();19if (!chunk) return;20running += 1;21await upload(chunk);22running -= 1;23}24}2526export async function upload(chunk: Chunk): Promise<UploadResult> {27const result = await sendChunk(chunk);28if (!result.ok) {29const delay = backoff.next(chunk.attempt);30if (delay === null) return fail(chunk);31return schedule(chunk, delay);32}33progress.advance(chunk.size);34return done(chunk);35}3637function schedule(chunk: Chunk, delay: number) {38chunk.attempt += 1;39progress.retrying(chunk);40setTimeout(() => enqueue([chunk]), delay);41}
あなたのマシンで動き、どこからでもつながる。
デスクトップアプリは手元のコンピューターでエージェントを動かし、あなたのサーバーにも接続します。スマートフォンは QR コードで一度ペアリングすれば、Private Relay 経由でサーバーにつながります。エンドツーエンドで暗号化され、ポートを開ける必要はありません。
uploaderで何に取り組みますか?
uploaderで何に取り組みますか?
uploaderで何に取り組みますか?
セッションが見つかりません。
const result = await sendChunk(chunk); if (!result.ok) { const delay = backoff.next(chunk.attempt); if (delay === null) return fail(chunk); return schedule(chunk, delay); }
const DELAYS = [500, 1000, 2000, 4000, 8000]; export const backoff = { next(attempt: number) { return DELAYS[attempt] ?? null; } };
test('retries a chunk after a 503', async () => { server.respondWith(503); await upload(chunk); clock.tick(500); expect(server.calls).toBe(2); });
ひとつのタスクを、複数のモデルで。
同じプロンプトを複数のモデルに一度に送れます。実行ごとに専用のワークツリーとブランチを持たせることもできます。気に入った結果を残すか、回答を1つにフュージョンしましょう。
大きな diff をウォークスルーで読む。
ウォークスルーは大きな diff を理解しやすい順に並べ直し、各ステップを一文で説明し、主要な変更に印を付けます。どこから読めばいいかがわかります。
チケットもツールも、ワンクリックで。
GitHub の issue、プルリクエスト、Linear のチケットからセッションを始めると、エージェントはスレッド全体を受け取ります。統合カタログには Figma や Sentry を含む 160 以上のサービスがあり、どれもワンクリックで入ります。
ゴールか、スケジュールを渡す。
ゴールを設定すると、別のチェックが完了または行き詰まりと判断するまで、エージェントはターンごとに作業を続けます。スケジュールしたタスクは、毎朝でも来週の火曜に一度だけでも、自分でセッションを始めます。
使っている人たちから。
頼んでいない投稿です。
I've had a deep experience with openchamber. I think my choice was right. This thing is really useful, smooth and silky. Go try it out quick, I strongly recommend it, no more messing around blindly.
@realchendahuang Was looking for a way to run agents from my phone, remotely on my server, other than tmux. Found OpenChamber. It is INSANELY good, highly recommended.
@NihilSineTheo Seriously, I've spent almost the whole week trying to find a tool that made sense to orchestrate agents and, as a dev (actually, a devops), openchamber is the only one that felt natural and logical.
@1un4rPunk I just want to say the app itself is phenomenal. The level of polish is just unreal. I saw OpenChamber back when it was a small project, I think maybe a couple months ago, and now it is unrecognizable. Truly amazing work. The latest release with its streaming feature is everything I could have possibly asked for and more. It is gorgeous and smooth.
いま手元にあるマシンにインストールする。
macOS、Windows、Linux ならデスクトップアプリ、サーバーならコマンドひとつ。あとはどこからでも開けます。
OpenChamber はあなたの作業について何も収集しません。コードは MIT ライセンスなので、誰でも確認できます。
アクティビティ
待ち時間を設定に出せますか? モバイルではもっと長くしたいかもしれません。
いいですね。待ち時間は 1 つの配列になったので、別の PR でできます。