다음을 통해 공유


Go용 Azure SDK의 일반적인 사용 패턴

Go용 Azure SDK의 Azure Core(azcore) 패키지는 SDK 전체에 적용되는 몇 가지 패턴을 구현합니다.

페이지 매김(컬렉션을 반환하는 메서드)

많은 Azure 서비스는 항목 컬렉션을 반환합니다. 항목 수가 클 수 있으므로 이러한 클라이언트 메서드는 페이저반환하므로 앱에서 한 번에 한 페이지의 결과를 처리할 수 있습니다. 이러한 형식은 다양한 컨텍스트에 대해 개별적으로 정의되지만 메서드와 같은 NextPage 일반적인 특성을 공유합니다.

예를 들어 .ListWidgetsWidgetPager 그런 다음 다음과 같이 사용합니다 WidgetPager .

func (c *WidgetClient) ListWidgets(options *ListWidgetOptions) WidgetPager {
    // ...
}

pager := client.ListWidgets(options)

for pager.NextPage(ctx) {
    for _, w := range pager.PageResponse().Widgets {
        process(w)
    }
}

if pager.Err() != nil {
    // Handle error...
}

장기 실행 작업

Azure의 일부 작업은 완료하는 데 몇 초에서 며칠까지 오랜 시간이 걸릴 수 있습니다. 이러한 작업의 예로는 원본 URL에서 스토리지 Blob으로 데이터를 복사하거나 AI 모델을 학습하여 양식을 인식하는 작업이 있습니다. 이러한 LLO(장기 실행 작업) 는 비교적 빠른 요청 및 응답의 표준 HTTP 흐름에 적합하지 않습니다.

규칙에 따라 LRO를 시작하는 메서드는 "Begin"이라는 접두사가 붙고 Poller를 반환합니다. Poller는 작업이 완료될 때까지 서비스를 주기적으로 폴링하는 데 사용됩니다.

다음 예제에서는 LRO를 처리하는 다양한 패턴을 보여 줍니다. SDK의 poller.go 소스 코드에서도 자세히 알아볼 수 있습니다.

PollUntilDone에 대한 호출 차단

PollUntilDone은 터미널 상태에 도달할 때까지 폴링 작업의 전체 범위를 처리합니다. 그런 다음 인터페이스에서 페이로드 respType 의 콘텐츠를 사용하여 폴링 작업에 대한 최종 HTTP 응답을 반환합니다.

resp, err := client.BeginCreate(context.Background(), "blue_widget", nil)

if err != nil {
    // Handle error...
}

w, err = resp.PollUntilDone(context.Background(), nil)

if err != nil {
    // Handle error...
}

process(w)

사용자 지정 폴링 루프

Poll 는 폴링 엔드포인트에 폴링 요청을 보내고 응답 또는 오류를 반환합니다.

resp, err := client.BeginCreate(context.Background(), "green_widget")

if err != nil {
    // Handle error...
}

poller := resp.Poller

for {
    resp, err := poller.Poll(context.Background())

    if err != nil {
        // Handle error...
    }

    if poller.Done() {
        break
    }

    // Do other work while waiting.
}

w, err := poller.FinalResponse(ctx)

if err != nil {
    // Handle error...
}

process(w)

이전 작업에서 다시 시작

기존 Poller에서 다시 시작 토큰을 추출하고 저장합니다.

폴링을 다시 시작하려면 다른 프로세스 또는 다른 컴퓨터에서 새 PollerResponse 인스턴스를 만든 다음 메서드를 Resume 호출하여 초기화하고 이전에 저장된 다시 시작 토큰을 전달합니다.

poller := resp.Poller
tk, err := poller.ResumeToken()

if err != nil {
    // Handle error...
}

resp = WidgetPollerResponse()

// Resume takes the resume token as an argument.
err := resp.Resume(tk, ...)

if err != nil {
    // Handle error...
}

for {
    resp, err := poller.Poll(context.Background())

    if err != nil {
        // Handle error...
    }

    if poller.Done() {
        break
    }

    // Do other work while waiting.
}

w, err := poller.FinalResponse(ctx)

if err != nil {
    // Handle error...
}

process(w)

HTTP 파이프라인 흐름

다양한 SDK 클라이언트는 AZURE의 REST API를 통해 추상화하여 코드 완성 및 컴파일 시간 형식 보안을 사용하도록 설정하므로 HTTP를 통해 하위 수준 전송 메커니즘을 처리할 필요가 없습니다. 그러나 전송 메커니즘(예: 재시도 및 로깅)을 사용자 지정할 수 있습니다.

SDK는 HTTP 파이프라인을 통해 HTTP 요청을 수행합니다. 파이프라인은 각 HTTP 요청-응답 왕복에 대해 수행되는 단계의 시퀀스를 설명합니다.

파이프라인은 몇 가지 정책과 함께 전송으로 구성됩니다.

  • 전송서비스에 요청을 보내고 응답을 받습니다.
  • policy는 파이프라인에서 특정 작업을 완료합니다.

다음 다이어그램은 파이프라인의 흐름을 보여 줍니다.

파이프라인의 흐름을 보여주는 다이어그램

모든 클라이언트 패키지는 이름이 인 azcoreCore 패키지를 공유합니다. 이 패키지는 순서가 지정된 정책 집합을 사용하여 HTTP 파이프라인을 생성하여 모든 클라이언트 패키지가 일관되게 작동하도록 합니다.

HTTP 요청을 보내면 요청이 HTTP 엔드포인트로 전송되기 전에 모든 정책이 파이프라인에 추가된 순서대로 실행됩니다. 이러한 정책은 일반적으로 요청 헤더를 추가하거나 나가는 HTTP 요청을 기록합니다.

Azure 서비스가 응답하면 응답이 코드로 반환되기 전에 모든 정책이 역순으로 실행됩니다. 대부분의 정책은 응답을 무시하지만 로깅 정책은 응답을 기록합니다. 재시도 정책은 요청을 다시 실행하여 앱이 네트워크 오류에 대한 복원력을 높일 수 있습니다.

각 정책에는 필요한 요청 또는 응답 데이터가 정책을 실행하는 데 필요한 컨텍스트와 함께 제공됩니다. 정책은 지정된 데이터를 사용하여 작업을 완료한 다음, 컨트롤을 파이프라인의 다음 정책에 전달합니다.

기본적으로 각 클라이언트 패키지는 해당 특정 Azure 서비스에서 작동하도록 구성된 파이프라인을 만듭니다. 자체 사용자 지정 정책을 정의하여 클라이언트를 만들 때 HTTP 파이프라인에 삽입할 수도 있습니다.

핵심 HTTP 파이프라인 정책

Core 패키지는 모든 파이프라인의 일부인 세 가지 HTTP 정책을 제공합니다.

사용자 지정 HTTP 파이프라인 정책

고유한 사용자 지정 정책을 정의하여 Core 패키지의 콘텐츠 이외의 기능을 추가할 수 있습니다. 예를 들어 앱이 네트워크 또는 서비스 오류를 처리하는 방법을 확인하려면 테스트 중에 요청이 수행되면 오류를 주입하는 정책을 만들 수 있습니다. 또는 테스트를 위해 서비스의 동작을 모의하는 정책을 만들 수 있습니다.

사용자 지정 HTTP 정책을 만들려면 Policy 인터페이스를 구현하는 Do 메서드를 사용하여 고유한 구조체를 정의합니다.

  1. 정책의 Do 메서드는 들어오는 policy.Request에서 필요에 따라 작업을 수행해야 합니다. 작업 예로 로깅, 실패 삽입 또는 요청의 URL, 쿼리 매개 변수 또는 요청 헤더 수정이 있습니다.
  2. 메서드는 Do 요청의 메서드를 호출하여 파이프라인의 다음 정책에 (수정된) 요청을 Next 전달합니다.
  3. Nexthttp.Response 및 오류를 반환합니다. 정책은 응답/오류 로깅과 같은 필요한 작업을 수행할 수 있습니다.
  4. 정책은 응답 및 오류를 파이프라인의 이전 정책에 반환해야 합니다.

참고 항목

정책은 goroutine-safe여야 합니다. Goroutine 안전 기능을 사용하면 여러 Goroutine이 단일 클라이언트 개체에 동시에 액세스할 수 있습니다. 정책을 만든 후에는 변경할 수 없는 것이 일반적입니다. 이 불변성은 고르투틴이 안전하다는 것을 보장합니다.

사용자 지정 정책 템플릿

다음 코드를 시작점으로 사용하여 사용자 지정 정책을 정의할 수 있습니다.

type MyPolicy struct {
    LogPrefix string
}

func (m *MyPolicy) Do(req *policy.Request) (*http.Response, error) {
	// Mutate/process request.
	start := time.Now()
	// Forward the request to the next policy in the pipeline.
	res, err := req.Next()
	// Mutate/process response.
	// Return the response & error back to the previous policy in the pipeline.
	record := struct {
		Policy   string
		URL      string
		Duration time.Duration
	}{
		Policy:   "MyPolicy",
		URL:      req.Raw().URL.RequestURI(),
		Duration: time.Duration(time.Since(start).Milliseconds()),
	}
	b, _ := json.Marshal(record)
	log.Printf("%s %s\n", m.LogPrefix, b)
	return res, err
}

func ListResourcesWithPolicy(subscriptionID string) error {
	cred, err := azidentity.NewDefaultAzureCredential(nil)
	if err != nil {
		return err
	}

	mp := &MyPolicy{
		LogPrefix: "[MyPolicy]",
	}
	options := &arm.ConnectionOptions{}
	options.PerCallPolicies = []policy.Policy{mp}
	options.Retry = policy.RetryOptions{
		RetryDelay: 20 * time.Millisecond,
	}

	con := arm.NewDefaultConnection(cred, options)
	if err != nil {
		return err
	}

	client := armresources.NewResourcesClient(con, subscriptionID)
	pager := client.List(nil)
	for pager.NextPage(context.Background()) {
		if err := pager.Err(); err != nil {
			log.Fatalf("failed to advance page: %v", err)
		}
		for _, r := range pager.PageResponse().ResourceListResult.Value {
			printJSON(r)
		}
	}
	return nil
}

사용자 지정 HTTP 전송

전송은 HTTP 요청을 보내고 응답/오류를 반환합니다. 요청을 처리하는 첫 번째 정책은 응답/오류를 파이프라인의 정책(역순)으로 다시 반환하기 전에 응답을 처리하는 마지막 정책이기도 합니다. 파이프라인의 마지막 정책은 전송을 호출합니다.

기본적으로 클라이언트는 Go의 표준 라이브러리에서 공유 http.Client 된 공유를 사용합니다.

사용자 지정 정책을 만드는 것과 동일한 방식으로 사용자 지정 상태 저장 또는 상태 비스테이션 전송을 만듭니다. 상태 저장의 경우 Transporter 인터페이스에서 상속된 메서드를 구현 Do 합니다. 두 경우 모두에서 함수 또는 Do 메서드에서 azcore.Request를 다시 받고 azCore.Response를 반환하고 정책과 동일한 순서로 작업을 수행합니다.

Azure 작업을 호출할 때 JSON 필드를 삭제하는 방법

JSON-MERGE-PATCH JSON null 을 보내 필드를 삭제해야 함을 나타내는 작업(해당 값과 함께).

{
    "delete-me": null
}

이 동작은 제외할 필드와 해당 0 값 사이의 모호성을 해결하는 방법으로 지정 omitempty 하는 SDK의 기본 마샬링과 충돌합니다.

type Widget struct {
    Name *string `json:",omitempty"`
    Count *int `json:",omitempty"`
}

앞의 예제에서 NameCount는 의미 체계상의 차이가 있을 수 있는 누락된 값(nil)과 0 값을 구분하기 위해 형식에 대한 포인터로 정의됩니다.

HTTP PATCH 작업에서 값 nil 이 있는 모든 필드는 서버 리소스의 값에 영향을 주지 않습니다. 위젯의 Count 필드를 업데이트할 때 새 값을 CountNamenil지정합니다.

JSON null을 보내기 위한 요구 사항을 충족하기 위해 함수가 NullValue 사용됩니다.

w := Widget{
    Count: azcore.NullValue(0).(*int),
}

이 코드는 Count를 명시적 JSON null로 설정합니다. 요청이 서버로 전송되면 리소스 필드 Count 가 삭제됩니다.

참고 항목