<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>동시성 on 얼쑤 · Team Edo</title><link>https://team-edo.github.io/tags/%EB%8F%99%EC%8B%9C%EC%84%B1/</link><description>Recent content in 동시성 on 얼쑤 · Team Edo</description><generator>Hugo</generator><language>ko-kr</language><lastBuildDate>Mon, 02 Nov 2026 00:00:00 +0900</lastBuildDate><atom:link href="https://team-edo.github.io/tags/%EB%8F%99%EC%8B%9C%EC%84%B1/index.xml" rel="self" type="application/rss+xml"/><item><title>저장한 녹음을 30일 삭제에서 빼기</title><link>https://team-edo.github.io/posts/2026/11/protect-saved-recordings-from-purge/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0900</pubDate><guid>https://team-edo.github.io/posts/2026/11/protect-saved-recordings-from-purge/</guid><description>&lt;p>얼쑤에서는 연주를 분석한 뒤 마음에 드는 기록을 저장하고 나중에 녹음을 다시 들을 수 있습니다. 처음에는 R2의 수명 주기 규칙이 녹음 객체를 생성한 지 30일이 지나면 삭제 대상으로 잡았습니다. 연습 기록을 저장했다는 사실은 DB에 있었기 때문에 같은 접두사 아래의 객체에 적용되는 규칙은 그 차이를 알 수 없었습니다. 저장한 녹음을 계속 들을 수 있게 하려면, 어떤 녹음을 정리할지 정하는 곳부터 바꿔야 했습니다. &lt;a href="https://developers.cloudflare.com/r2/buckets/object-lifecycles/">Cloudflare R2의 객체 수명 주기&lt;/a>&lt;/p></description></item><item><title>학습의 첫 완료 시각 지키기</title><link>https://team-edo.github.io/posts/2026/11/keep-first-lesson-completion/</link><pubDate>Mon, 02 Nov 2026 00:00:00 +0900</pubDate><guid>https://team-edo.github.io/posts/2026/11/keep-first-lesson-completion/</guid><description>&lt;p>얼쑤의 기초 학습에서 사용자는 단계를 끝낸 뒤 완료를 표시할 수 있습니다. 같은 단계를 다시 표시해도 처음 완료한 시각은 유지하기로 했습니다. 서버가 저장한 직후 응답이 끊겨 앱이 같은 요청을 다시 보낼 수 있고, 두 번 누른 요청이 거의 함께 도착할 수도 있기 때문입니다.&lt;/p>
&lt;h2 id="두-번째-요청은-시각을-갱신하지-않는다">중복 완료는 시각 유지&lt;/h2>
&lt;p>완료 여부의 범위는 회원과 학습 단계의 조합입니다. DB의 유일 키가 그 조합을 하나로 제한합니다. 처음에는 회원, 단계, 완료 시각을 삽입합니다. 같은 조합이 이미 있으면 &lt;code>ON DUPLICATE KEY UPDATE&lt;/code>에서 기존 ID를 자기 자신으로 대입해 값을 유지합니다. 서버가 각 요청을 다른 시각에 받더라도 저장된 시각은 한 번만 정해집니다.&lt;/p></description></item><item><title>상태 조회가 대기 녹음을 지울 수 있던 이유</title><link>https://team-edo.github.io/posts/2026/10/keep-pending-recordings-until-upload/</link><pubDate>Thu, 29 Oct 2026 00:00:00 +0900</pubDate><guid>https://team-edo.github.io/posts/2026/10/keep-pending-recordings-until-upload/</guid><description>&lt;p>연주를 끝낸 직후 연결이 끊기면, 아직 서버에 도착하지 않은 녹음을 다시 보낼 수 있어야 합니다. 얼쑤에서는 녹음 파일을 기기의 보관 위치로 옮긴 다음, 어느 세션에 어떤 파일을 보낼지 기록하고 업로드하도록 만들었습니다. 앱을 다시 열어도 그 기록에서 보낼 녹음을 찾을 수 있습니다.&lt;/p>
&lt;p>리뷰에서 파일을 옮기는 일과 대기 기록을 저장하는 일 사이에 틈이 있다는 걸 발견했습니다. 새 파일은 이미 보관 위치에 있지만, 상태 조회에서 읽을 대기 기록은 아직 없습니다. 기존 조회 함수는 기록이 없으면 보관 폴더에 남은 파일을 정리했습니다. 이 순간에 조회가 끼어들면 방금 옮긴 녹음도 버려도 되는 파일로 보고 지울 수 있었습니다.&lt;/p></description></item><item><title>Jira 작업 생성 뒤 다시 읽는 이유</title><link>https://team-edo.github.io/posts/2026/10/verify-jira-task-after-create/</link><pubDate>Wed, 28 Oct 2026 00:00:00 +0900</pubDate><guid>https://team-edo.github.io/posts/2026/10/verify-jira-task-after-create/</guid><description>&lt;p>개발 작업을 시작할 때 Jira에 작업을 만들고 담당자와 스프린트를 지정했습니다. 생성할 때 필드를 한꺼번에 보내면 요청 한 번으로 끝날 거라고 생각했습니다. 당시 사용한 연결 도구에서는 스프린트 값을 포함한 생성 요청이 &lt;strong>HTTP 400&lt;/strong>으로 거절됐습니다. 값을 빼고 작업을 만들자 요청은 성공했지만, 응답에 적힌 담당자는 요청에 넣은 사람과 달랐습니다. 요청을 받아들였는지와 기대한 값이 남았는지를 따로 확인해야 했습니다.&lt;/p>
&lt;h2 id="생성과-배정을-분리했다">생성과 배정을 나눠 재조회&lt;/h2>
&lt;p>먼저 스프린트 값을 빼고 작업을 만들었습니다. 생성 응답에서 실제 작업을 가리키는 키를 얻은 뒤, 그 작업에 상태 전환과 스프린트 배정을 요청했습니다. 생성 응답에서 다르게 표시된 담당자도 확인해 수정했습니다. 담당자가 바뀐 이유로 프로젝트 기본값을 의심했지만, 어느 설정이 적용됐는지까지는 확인하지 못했습니다.&lt;/p></description></item><item><title>동시 업로드에서 접수된 녹음만 남기기</title><link>https://team-edo.github.io/posts/2026/10/concurrent-upload-keep-winning-object/</link><pubDate>Wed, 28 Oct 2026 00:00:00 +0900</pubDate><guid>https://team-edo.github.io/posts/2026/10/concurrent-upload-keep-winning-object/</guid><description>&lt;p>얼쑤에서 녹음을 올리면 서버는 파일을 객체 저장소에 쓴 뒤, 세션에 원본의 키를 기록하고 상태를 &lt;code>PENDING&lt;/code>으로 바꿉니다. 같은 세션에 업로드 요청이 거의 동시에 오면 두 요청 모두 처음에는 상태를 &lt;code>RECORDING&lt;/code>으로 읽을 수 있습니다. DB에서 한 요청만 접수하더라도 저장소에는 두 요청 모두 파일을 쓰는 시점이 생깁니다.&lt;/p>
&lt;p>세션마다 고정된 객체 키를 쓴다고 가정해 봤습니다. 요청 A가 먼저 DB 갱신을 마쳐도, 요청 B가 같은 키에 늦게 쓰면 DB가 가리키는 파일은 B의 바이트가 됩니다. B가 갱신에 실패하고 자신이 쓴 파일을 지우는 경우에도 같은 키라 A의 원본이 사라집니다. DB가 접수 순서를 정하는 것과 별도로, 어느 요청이 어느 파일을 소유하는지 저장소에서도 구분해야 했습니다.&lt;/p></description></item><item><title>동시 요청 네 건, 연습 세션 한 개</title><link>https://team-edo.github.io/posts/2026/10/practice-session-idempotency/</link><pubDate>Wed, 28 Oct 2026 00:00:00 +0900</pubDate><guid>https://team-edo.github.io/posts/2026/10/practice-session-idempotency/</guid><description>&lt;p>앱이 연습 세션을 만들라는 요청을 보냈는데 응답을 받기 전에 연결이 끊겼다고 가정해 봅시다. 서버에서는 이미 저장을 마쳤을 수도 있습니다. 앱이 같은 요청을 다시 보냈을 때 새 세션을 만들면 한 번의 연습에 세션이 두 개 생깁니다. 얼쑤에서는 앱이 재전송에도 같은 &lt;code>Idempotency-Key&lt;/code>를 쓰도록 하고, 서버는 같은 회원·키로 만들어진 세션을 다시 돌려주도록 했습니다.&lt;/p>
&lt;h2 id="두-요청이-모두-아직-없음을-볼-수-있다">중복 삽입을 막는 유일 제약&lt;/h2>
&lt;p>키가 들어오면 먼저 같은 회원이 그 키를 쓴 적이 있는지 조회합니다. 이미 세션이 있으면 저장 단계까지 갈 필요가 없습니다. 다만 두 요청이 거의 함께 오면 둘 다 저장 전에 조회를 마치고 “아직 없음”으로 판단할 수 있습니다.&lt;/p></description></item></channel></rss>