에러
분류와 재시도 메타데이터가 있는 구조화된 에러 처리. 전역 errors 테이블은 require 없이 사용 가능합니다.
에러 생성
-- 간단한 메시지 (kind 기본값은 UNKNOWN)
local err = errors.new("something went wrong")
-- kind와 함께
local err = errors.new(errors.NOT_FOUND, "user not found")
-- 전체 생성자
local err = errors.new({
message = "user not found",
kind = errors.NOT_FOUND,
retryable = false,
details = {user_id = 123}
})
에러 래핑
kind, retryable, details를 보존하면서 컨텍스트 추가:
local data, err = db.query("SELECT * FROM users")
if err then
return nil, errors.wrap(err, "failed to load users")
end
에러 메서드
| 메서드 | 반환 | 설명 |
|---|---|---|
err:kind() |
string | 에러 카테고리 |
err:message() |
string | 에러 메시지 |
err:retryable() |
boolean/nil | 작업을 재시도할 수 있는지 |
err:details() |
table/nil | 구조화된 메타데이터 |
err:stack() |
string | Lua 스택 트레이스 |
tostring(err) |
string | 전체 표현 |
Kind 확인
if errors.is(err, errors.INVALID) then
-- 잘못된 입력 처리
end
-- 또는 직접 비교
if err:kind() == errors.NOT_FOUND then
-- 누락된 리소스 처리
end
에러 종류
| 상수 | 사용 사례 |
|---|---|
errors.NOT_FOUND |
리소스가 존재하지 않음 |
errors.ALREADY_EXISTS |
리소스가 이미 존재 |
errors.INVALID |
잘못된 입력 또는 인자 |
errors.PERMISSION_DENIED |
접근 거부됨 |
errors.UNAVAILABLE |
서비스가 일시적으로 다운 |
errors.INTERNAL |
내부 에러 |
errors.CANCELED |
작업이 취소됨 |
errors.CONFLICT |
리소스 상태 충돌 |
errors.TIMEOUT |
작업 시간 초과 |
errors.RATE_LIMITED |
요청이 너무 많음 |
errors.UNKNOWN |
지정되지 않은 에러 |
호출 스택
구조화된 호출 스택 가져오기:
local stack = errors.call_stack(err)
if stack then
print("Thread:", stack.thread)
for _, frame in ipairs(stack.frames) do
print(frame.source .. ":" .. frame.line, frame.name)
end
end
재시도 가능한 에러
| 일반적으로 재시도 가능 | 재시도 불가 |
|---|---|
TIMEOUT |
INVALID |
UNAVAILABLE |
NOT_FOUND |
RATE_LIMITED |
PERMISSION_DENIED |
ALREADY_EXISTS |
if err:retryable() then
-- 재시도 안전
end
에러 상세
local err = errors.new({
message = "validation failed",
kind = errors.INVALID,
details = {
errors = {
{field = "email", message = "invalid format"},
{field = "age", message = "must be positive"}
}
}
})
local details = err:details()
for _, e in ipairs(details.errors) do
print(e.field, e.message)
end