Skip to content
isdnetworks
Go back

예외를 던지니 호출처가 롤백한다

(수정됨)

유령 레코드가 나왔다.

복제 과정은 저장됨
첨부 파일은 없음

Table of contents

Open Table of contents

증상 — 유령 레코드와 후보

중간에 죽은 흔적이라 create_child_course 가 의심스러웠다.

public function create_child_course($master)
{
    // 복제 과정 저장
    // 첨부 파일 복사
}

create_child_course 가 저장 뒤에 복사를 한다.

복사가 실패하면 저장만 남아 유령 레코드가 되는 구조여서 여기에 트랜잭션을 넣어야 하나 싶었다.

판단 기준 — 실패가 무엇으로 오는가

트랜잭션을 넣기 전에 하나를 먼저 확인했다.

$fs->create_file_from_storedfile($record, $source);

create_file_from_storedfile 이 거짓을 반환하는지 예외를 던지는지가 갈린다.

[거짓 반환]  조용히 실패 → 다음 줄로 넘어감 → 유령 레코드
[예외]       중단 → 호출처로 전파

이 한 가지로 결론이 정반대가 된다.

검증 — 소스를 직접 읽었다

Moodle 의 lib/filestorage/file_storage.php 를 직접 열었다.

public function create_file_from_storedfile($filerecord, $fileorid) {
    ...
    if (!$fs->file_exists(...)) {
        throw new file_exception('storedfileproblem', 'File does not exist');   // 여기
    }

원본이 없으면 file_exception 을 던지고 레코드의 contextid 나 filearea 가 틀려도 같은 예외다.

문서에는 반환값과 예외가 명확하지 않았다. 문서만 보는 것 대신 소스를 읽는 쪽을 골랐다. 이유는 동작을 확정하려면 던지는 자리를 직접 봐야 하고 그 자리는 문서에 없어서다.

결과 — 호출처 넷 중 셋

file_exception 이 어디로 가는지 봤다.

grep -rn "create_child_course" local/

create_child_course 를 부르는 자리가 넷 나왔다.

// course_controller.php:206
$tx = $DB->start_delegated_transaction();
try {
    $service->create_child_course($master);
    $tx->allow_commit();
} catch (Exception $e) {
    $tx->rollback($e);
}

트랜잭션으로 감싸고 예외면 rollback 을 부른다.

course_controller.php:206      감쌈
course_import.php:136          감쌈
course_import.php:204          감쌈
course_migration.php:124       안 감쌈   ← 하나

넷 중 셋이 이미 감싸고 있었다.

결론 — 안 넣기로 했다

롤백 경로가 이미 성립하고 있었다.

복사 실패
    ↓ file_exception
함수를 빠져나감
    ↓
호출처가 rollback

여기서 함수 안에 트랜잭션을 새로 넣었으면 중첩을 만들 뻔했다.

[전]  이 함수가 유령 레코드의 원인일 수 있음
[후]  호출처 네 곳 중 한 곳만 미보호

봐야 할 곳이 course_migration.php 한 곳으로 좁혀졌다.

교훈 — 용의자를 지우는 것

이번 유령 레코드가 course_migration.php 경로에서 나온 것인지도 확인했다.

아니었고 다른 경로에서 온 것이어서 이 함수는 이번 건의 원인이 아니었다.

[안 확인했으면]  여기에 트랜잭션 넣고 → 유령 레코드 또 나옴
[확인했으니]     여기를 지우고 다른 데를 봄

원인을 찾는 것과 원인이 아닌 것을 지우는 것이 둘 다 필요하다. 여기가 의심스러우니 일단 고쳐 두자로 가면 안 고쳐졌을 때 처음부터 다시 본다. 원인을 못 찾았어도 용의자를 지우는 것은 분명한 진전이었다.

정리


Share this post on:

Previous Post
저장소가 몇 개인지부터 적었다
Next Post
단계가 드러나는 폴더 구조