Golang에서 CLI 애플리케이션의 오류 처리
15847 단어 go
main.go
파일을 "내 애플리케이션의 입력 및 출력 포트"로 간주합니다.왜 입력 포트입니까? 이것은
main.go
파일에 있으며, 이 파일을 컴파일하여 응용 프로그램의 실행 파일을 생성하고 여기에서 다른 모든 패키지를 "바인딩"합니다. main.go
는 종속성을 시작하고 비즈니스 논리를 수행하는 패키지를 구성 및 호출하는 곳입니다.예를 들어:
package main
import (
"database/sql"
"errors"
"fmt"
"log"
"os"
"github.com/eminetto/clean-architecture-go-v2/infrastructure/repository"
"github.com/eminetto/clean-architecture-go-v2/usecase/book"
"github.com/eminetto/clean-architecture-go-v2/config"
_ "github.com/go-sql-driver/mysql"
"github.com/eminetto/clean-architecture-go-v2/pkg/metric"
)
func handleParams() (string, error) {
if len(os.Args) < 2 {
return "", errors.New("Invalid query")
}
return os.Args[1], nil
}
func main() {
metricService, err := metric.NewPrometheusService()
if err != nil {
log.Fatal(err.Error())
}
appMetric := metric.NewCLI("search")
appMetric.Started()
query, err := handleParams()
if err != nil {
log.Fatal(err.Error())
}
dataSourceName := fmt.Sprintf("%s:%s@tcp(%s:3306)/%s?parseTime=true", config.DB_USER, config.DB_PASSWORD, config.DB_HOST, config.DB_DATABASE)
db, err := sql.Open("mysql", dataSourceName)
if err != nil {
log.Fatal(err.Error())
}
defer db.Close()
repo := repository.NewBookMySQL(db)
service := book.NewService(repo)
all, err := service.SearchBooks(query)
if err != nil {
log.Fatal(err)
}
//other logic to handle the data
appMetric.Finished()
err = metricService.SaveCLI(appMetric)
if err != nil {
log.Fatal(err)
}
}
여기에서 데이터베이스에 대한 연결을 구성하고, 서비스를 인스턴스화하고, 종속성을 전달하는 등의 작업을 수행합니다.
그리고 왜 애플리케이션의 출력 포트입니까?
main.go
의 다음 스니펫을 고려하십시오. repo := repository.NewBookMySQL(db)
service := book.NewService(repo)
all, err := service.SearchBooks(query)
if err != nil {
log.Fatal(err)
}
SearchBooks
에서 Service
함수의 내용을 분석해 보겠습니다.func (s *Service) SearchBooks(query string) ([]*entity.Book, error) {
books, err := s.repo.Search(strings.ToLower(query))
if err != nil {
return nil, fmt.Errorf("executing search: %w", err)
}
if len(books) == 0 {
return nil, entity.ErrNotFound
}
return books, nil
}
저장소의 다른 함수
Search
를 호출합니다. 이 함수의 코드는 다음과 같습니다.func (r *BookMySQL) Search(query string) ([]*entity.Book, error) {
stmt, err := r.db.Prepare(`select id, title, author, pages, quantity, created_at from book where title like ?`)
if err != nil {
return nil, err
}
var books []*entity.Book
rows, err := stmt.Query("%" + query + "%")
if err != nil {
return nil, fmt.Errorf("parsing query: %w", err)
}
for rows.Next() {
var b entity.Book
err = rows.Scan(&b.ID, &b.Title, &b.Author, &b.Pages, &b.Quantity, &b.CreatedAt)
if err != nil {
return nil, fmt.Errorf("scan: %w", err)
}
books = append(books, &b)
}
return books, nil
}
이 두 함수는 흐름을 중단하고 오류 수신 시 가능한 한 빨리 반환한다는 공통점이 있습니다. 그들은
panic
또는 os.Exit
와 같은 일부 기능을 사용하여 실행을 기록하거나 중지하려고 시도하지 않습니다. 이 절차는 main.go
의 책임입니다. 이 예는 실행만 하지만log.Fatal(err),
일부 외부 서비스에 로그를 보내거나 모니터링을 위해 일부 경고를 생성하는 것과 같은 고급 논리를 사용할 수 있습니다. 이렇게 하면 main.go
에서 처리가 중앙 집중화되므로 메트릭을 수집하고 고급 오류 처리 등을 수행하는 것이 훨씬 쉽습니다.내부 함수에서 실행
os.Exit
할 때 특히 주의하십시오. os.Exit
를 사용하면 응용 프로그램이 즉시 중지되고 defer
에서 사용한 모든 main.go
가 무시됩니다. 이 예에서 SearchBooks
함수가 os.Exit
를 실행하면 defer db.Close()
의 main.go
가 무시되어 데이터베이스에 문제가 발생할 수 있습니다.이것이 권장되는 커뮤니티 표준이라는 문서를 읽은 기억이 없지만 성공적으로 사용한 사례입니다. 이 접근법에 동의하십니까? 다른 의견도 환영합니다.
Reference
이 문제에 관하여(Golang에서 CLI 애플리케이션의 오류 처리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/eminetto/error-handling-of-cli-applications-in-golang-4c7l텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)