다음을 통해 공유


Azure Functions Node.js 개발자 가이드

이 가이드는 JavaScript 또는 TypeScript를 사용하여 Azure Functions를 개발하는 방법을 소개합니다. 이 문서에서는 Azure Functions 개발자 가이드를 이미 읽었다고 가정합니다.

Important

이 문서의 콘텐츠는 이 페이지 상단의 선택기에서 선택한 Node.js 프로그래밍 모델에 따라 변경됩니다. 선택한 버전은 앱에서 사용 중인 @azure/functions npm 패키지의 버전과 일치해야 합니다. package.json에 나열된 해당 패키지가 없는 경우 기본값은 v3입니다. 마이그레이션 가이드에서 v3과 v4의 차이점에 대해 자세히 알아봅니다.

Node.js 개발자는 다음 문서 중 하나에 관심이 있을 수도 있습니다.

시작하기 개념 학습 도우미

고려 사항

  • Node.js 프로그래밍 모델을 Azure Functions 런타임과 혼동하면 안 됩니다.
    • 프로그래밍 모델: 코드를 작성하는 방법을 정의하고 JavaScript 및 TypeScript에만 적용됩니다.
    • 런타임: Azure Functions의 기본 동작을 정의하고 모든 언어에서 공유됩니다.
  • 프로그래밍 모델 버전은 @azure/functions npm 패키지 버전과 엄격하게 연결되어 있습니다. 런타임과 독립적으로 버전이 지정됩니다. 런타임과 프로그래밍 모델 모두 최신 주 버전으로 숫자 4를 사용하지만 이는 우연의 일치입니다.
  • 동일한 함수 앱에서 v3 및 v4 프로그래밍 모델을 혼합할 수 없습니다. 앱에 하나의 v4 함수를 등록하는 즉시 function.json 파일에 등록된 모든 v3 함수는 무시됩니다.

지원되는 버전

다음 표에는 지원되는 Azure Functions 런타임 및 Node.js 버전과 함께 Node.js 프로그래밍 모델의 각 버전이 나와 있습니다.

프로그래밍 모델 버전 지원 수준 Functions 런타임 버전 Node.js 버전 설명
4.x GA 4.25+ 20.x, 18.x 유연한 파일 구조와 트리거 및 바인딩에 대한 코드 중심 방식을 지원합니다.
3.x GA 4.x 20.x, 18.x, 16.x, 14.x "function.json" 파일에 선언된 트리거 및 바인딩이 포함된 특정 파일 구조가 필요합니다.
2.x 해당 없음 3.x 14.x, 12.x, 10.x 2022년 12월 13일에 지원이 종료되었습니다. 자세한 내용은 함수 버전을 참조하세요.
1.x 해당 없음 2.x 10.x, 8.x 2022년 12월 13일에 지원이 종료되었습니다. 자세한 내용은 함수 버전을 참조하세요.

폴더 구조

JavaScript 프로젝트에 필요한 폴더 구조는 다음 예제와 같습니다.

<project_root>/
 | - .vscode/
 | - node_modules/
 | - myFirstFunction/
 | | - index.js
 | | - function.json
 | - mySecondFunction/
 | | - index.js
 | | - function.json
 | - .funcignore
 | - host.json
 | - local.settings.json
 | - package.json

기본 프로젝트 폴더(<project_root>)에는 다음 파일이 포함될 수 있습니다.

  • .vscode/:(선택 사항) 저장된 Visual Studio Code 구성을 포함합니다. 자세한 내용은 Visual Studio Code 설정을 참조하세요.
  • myFirstFunction/function.json: 함수의 트리거, 입력 및 출력에 대한 구성을 포함합니다. 디렉터리 이름에 따라 함수 이름이 결정됩니다.
  • myFirstFunction/index.js: 함수 코드를 저장합니다. 이 기본 파일 경로를 변경하려면 scriptFile 사용을 참조하세요.
  • .funcignore: (선택 사항) Azure에 게시하면 안 되는 파일을 선언합니다. 일반적으로 이 파일에는 편집기 설정을 무시하는 .vscode/, 테스트 사례를 무시하는 test/ 및 로컬 앱 설정을 게시하지 않도록 하는 local.settings.json이 포함되어 있습니다.
  • host.json: 함수 앱 인스턴스의 모든 함수에 영향을 미치는 구성 옵션이 포함되어 있습니다. 이 파일은 Azure에 게시됩니다. 로컬로 실행할 경우 일부 옵션이 지원되지 않습니다. 자세한 내용은 host.json을 참조하세요.
  • local.settings.json: 로컬에서 실행될 때 앱 설정과 연결 문자열을 저장하는 데 사용됩니다. 이 파일은 Azure에 게시되지 않습니다. 자세한 내용은 local.settings.file을 참조하세요.
  • package.json: 패키지 종속성 목록, 기본 진입점 및 스크립트와 같은 구성 옵션을 포함합니다.

JavaScript 프로젝트에 권장되는 폴더 구조는 다음 예와 같습니다.

<project_root>/
 | - .vscode/
 | - node_modules/
 | - src/
 | | - functions/
 | | | - myFirstFunction.js
 | | | - mySecondFunction.js
 | - test/
 | | - functions/
 | | | - myFirstFunction.test.js
 | | | - mySecondFunction.test.js
 | - .funcignore
 | - host.json
 | - local.settings.json
 | - package.json

기본 프로젝트 폴더(<project_root>)에는 다음 파일이 포함될 수 있습니다.

  • .vscode/:(선택 사항) 저장된 Visual Studio Code 구성을 포함합니다. 자세한 내용은 Visual Studio Code 설정을 참조하세요.
  • src/functions/: 모든 함수와 관련 트리거 및 바인딩의 기본 위치입니다.
  • tests/: (선택 사항) 함수 앱의 테스트 사례를 포함합니다.
  • .funcignore: (선택 사항) Azure에 게시하면 안 되는 파일을 선언합니다. 일반적으로 이 파일에는 편집기 설정을 무시하는 .vscode/, 테스트 사례를 무시하는 test/ 및 로컬 앱 설정을 게시하지 않도록 하는 local.settings.json이 포함되어 있습니다.
  • host.json: 함수 앱 인스턴스의 모든 함수에 영향을 미치는 구성 옵션이 포함되어 있습니다. 이 파일은 Azure에 게시됩니다. 로컬로 실행할 경우 일부 옵션이 지원되지 않습니다. 자세한 내용은 host.json을 참조하세요.
  • local.settings.json: 로컬에서 실행될 때 앱 설정과 연결 문자열을 저장하는 데 사용됩니다. 이 파일은 Azure에 게시되지 않습니다. 자세한 내용은 local.settings.file을 참조하세요.
  • package.json: 패키지 종속성 목록, 기본 진입점 및 스크립트와 같은 구성 옵션을 포함합니다.

함수 등록

v3 모델은 두 파일의 존재에 따라 함수를 등록합니다. 먼저 앱의 루트에서 한 수준 아래 폴더에 있는 function.json 파일이 필요합니다. 둘째, 함수를 내보내는 JavaScript 파일이 필요합니다. 기본적으로 모델은 function.json와 동일한 폴더에 있는 index.js 파일을 찾습니다. TypeScript를 사용하는 경우 function.jsonscriptFile 속성을 사용하여 컴파일된 JavaScript 파일을 가리켜야 합니다. 함수의 파일 위치 또는 내보내기 이름을 사용자 지정하려면 함수의 진입점 구성을 참조하세요.

내보내는 함수는 항상 v3 모델에서 async function로 선언되어야 합니다. 동기 함수를 내보낼 수 있지만 context.done()를 호출하여 함수가 완료되었다는 신호를 보내야 합니다. 이는 사용되지 않으며 권장되지 않습니다.

함수는 첫 번째 인수로 호출 context를 전달하고 나머지 인수로 입력을 전달합니다.

다음 예는 트리거되었음을 로그하고 Hello, world!로 응답하는 간단한 함수입니다.

{
  "bindings": [
    {
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "authLevel": "anonymous",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ]
}
module.exports = async function (context, request) {
    context.log('Http function was triggered.');
    context.res = { body: 'Hello, world!' };
};

프로그래밍 모델은 package.jsonmain 필드를 기반으로 함수를 로드합니다. GLOB 패턴을 사용하여 main 필드를 단일 파일 또는 여러 파일로 설정할 수 있습니다. 다음 표에서는 main 필드의 예제 값을 보여 줍니다.

예제 설명
src/index.js 단일 루트 파일에서 함수를 등록합니다.
src/functions/*.js 자체 파일에서 각 함수를 등록합니다.
src/{index.js,functions/*.js} 자체 파일에서 각 함수를 등록하지만 일반 앱 수준 코드에 대한 루트 파일이 있는 조합입니다.

함수를 등록하려면 @azure/functions npm 모듈에서 app 개체를 가져와서 트리거 형식에 특정한 메서드를 호출해야 합니다. 함수를 등록할 때 첫 번째 인수는 함수 이름입니다. 두 번째 인수는 트리거, 처리기 및 기타 모든 입력 또는 출력에 대한 구성을 지정하는 options 개체입니다. 트리거 구성이 필요하지 않은 일부 경우 options 개체 대신 처리기를 두 번째 인수로 직접 전달할 수 있습니다.

해당 파일이 package.json 파일의 main 필드를 기반으로(직접 또는 간접적으로) 로드되는 한 프로젝트의 모든 파일에서 함수를 등록할 수 있습니다. 실행이 시작된 후에는 함수를 등록할 수 없으므로 함수를 전역 범위에 등록해야 합니다.

다음 예는 트리거되었음을 로그하고 Hello, world!로 응답하는 간단한 함수입니다.

const { app } = require('@azure/functions');

app.http('helloWorld1', {
    methods: ['POST', 'GET'],
    handler: async (request, context) => {
        context.log('Http function was triggered.');
        return { body: 'Hello, world!' };
    }
});

입력 및 출력

함수에는 트리거라는 기본 입력이 정확히 하나 있어야 합니다. 보조 입력 및/또는 출력을 가질 수도 있습니다. 입력 및 출력은 function.json 파일에서 구성되며 바인딩이라고도 합니다.

입력

입력은 directionin로 설정된 바인딩입니다. 트리거와 보조 입력 간의 주요 차이점은 트리거의 typeTrigger로 끝나는 것입니다(예: blobTrigger 형식과 blob 형식 비교). 대부분의 함수는 트리거만 사용하며 많은 보조 입력 형식이 지원되지 않습니다.

입력은 다음과 같은 여러 가지 방법으로 액세스할 수 있습니다.

  • [권장] 함수에 전달된 인수:function.json에 정의된 것과 동일한 순서로 인수를 사용합니다. function.json에 정의된 name 속성은 조직을 위해 권장되지만 인수의 이름과 일치할 필요는 없습니다.

    module.exports = async function (context, myTrigger, myInput, myOtherInput) { ... };
    
  • context.bindings의 속성:function.json에 정의된 name 속성과 일치하는 키를 사용합니다.

    module.exports = async function (context) {
        context.log("This is myTrigger: " + context.bindings.myTrigger);
        context.log("This is myInput: " + context.bindings.myInput);
        context.log("This is myOtherInput: " + context.bindings.myOtherInput);
    };
    

출력

출력은 directionout로 설정된 바인딩이며 다음과 같은 여러 가지 방법으로 설정할 수 있습니다.

  • [단일 출력에 권장] 값을 직접 반환: 비동기 함수를 사용하는 경우 값을 직접 반환할 수 있습니다. 다음 예제와 같이 출력 바인딩의 name 속성을 $return에서 function.json으로 변경해야 합니다.

    {
        "name": "$return",
        "type": "http",
        "direction": "out"
    }
    
    module.exports = async function (context, request) {
        return {
            body: "Hello, world!"
        };
    }
    
  • [여러 출력에 권장] 모든 출력을 포함하는 개체 반환: 비동기 함수를 사용하는 경우 function.json의 각 바인딩 이름과 일치하는 속성이 있는 개체를 반환할 수 있습니다. 다음 예제에서는 "httpResponse" 및 "queueOutput"이라는 출력 바인딩을 사용합니다.

    {
        "name": "httpResponse",
        "type": "http",
        "direction": "out"
    },
    {
        "name": "queueOutput",
        "type": "queue",
        "direction": "out",
        "queueName": "helloworldqueue",
        "connection": "storage_APPSETTING"
    }
    
    module.exports = async function (context, request) {
        let message = 'Hello, world!';
        return {
            httpResponse: {
                body: message
            },
            queueOutput: message
        };
    };
    
  • context.bindings에서 값 설정: 비동기 함수를 사용하지 않거나 이전 옵션을 사용하지 않으려는 경우 키가 바인딩 이름과 일치하는 context.bindings에서 직접 값을 설정할 수 있습니다. 다음 예제에서는 "httpResponse" 및 "queueOutput"이라는 출력 바인딩을 사용합니다.

    {
        "name": "httpResponse",
        "type": "http",
        "direction": "out"
    },
    {
        "name": "queueOutput",
        "type": "queue",
        "direction": "out",
        "queueName": "helloworldqueue",
        "connection": "storage_APPSETTING"
    }
    
    module.exports = async function (context, request) {
        let message = 'Hello, world!';
        context.bindings.httpResponse = {
            body: message
        };
        context.bindings.queueOutput = message;
    };
    

바인딩 데이터 형식

입력 바인딩에서 dataType 속성을 사용하여 입력 유형을 변경할 수 있지만 몇 가지 제한 사항이 있습니다.

  • Node.js에서는 stringbinary만 지원됩니다(stream은 지원되지 않음).
  • HTTP 입력의 경우 dataType 속성은 무시됩니다. 대신 request 개체의 속성을 사용하여 원하는 형식으로 본문을 가져옵니다. 자세한 내용은 HTTP 요청을 참조하세요.

스토리지 큐 트리거의 다음 예제에서 myQueueItem의 기본 형식은 string이지만 dataTypebinary로 설정하면 형식이 Node.js Buffer로 변경됩니다.

{
    "name": "myQueueItem",
    "type": "queueTrigger",
    "direction": "in",
    "queueName": "helloworldqueue",
    "connection": "storage_APPSETTING",
    "dataType": "binary"
}
const { Buffer } = require('node:buffer');

module.exports = async function (context, myQueueItem) {
    if (typeof myQueueItem === 'string') {
        context.log('myQueueItem is a string');
    } else if (Buffer.isBuffer(myQueueItem)) {
        context.log('myQueueItem is a buffer');
    }
};

함수에는 트리거라는 기본 입력이 정확히 하나 있어야 합니다. 또한 보조 입력, 반환 출력이라고 하는 기본 출력 및/또는 보조 출력이 있을 수 있습니다. 입출력은 Node.js 프로그래밍 모델의 컨텍스트 외부에서 바인딩이라고도 합니다. 모델 v4 이전에는 이러한 바인딩이 function.json 파일에 구성되었습니다.

트리거 입력

트리거는 유일한 필수 입력 또는 출력입니다. 대부분의 트리거 형식의 경우 트리거 형식 다음에 이름이 지정된 app 개체의 메서드를 사용하여 함수를 등록합니다. options 인수에서 직접 트리거에 특정한 구성을 지정할 수 있습니다. 예를 들어, HTTP 트리거를 사용하면 경로를 지정할 수 있습니다. 실행 중에 이 트리거에 해당하는 값이 처리기의 첫 번째 인수로 전달됩니다.

const { app } = require('@azure/functions');

app.http('helloWorld1', {
    route: 'hello/world',
    handler: async (request, context) => {
        ...
    }
});

반환 출력

반환 출력은 선택 사항이며 경우에 따라 기본적으로 구성됩니다. 예를 들어, app.http에 등록된 HTTP 트리거는 HTTP 응답 출력을 자동으로 반환하도록 구성됩니다. 대부분의 출력 형식의 경우 @azure/functions 모듈에서 내보낸 output 개체의 도움으로 options 인수에 반환 구성을 지정합니다. 실행하는 동안 처리기에서 반환하여 이 출력을 설정합니다.

다음 예제에서는 타이머 트리거스토리지 큐 출력을 사용합니다.

const { app, output } = require('@azure/functions');

app.timer('timerTrigger1', {
    schedule: '0 */5 * * * *',
    return: output.storageQueue({
        connection: 'storage_APPSETTING',
        ...
    }),
    handler: (myTimer, context) => {
        return { hello: 'world' }
    }
});

추가 입력 및 출력

트리거 및 반환 외에도 함수를 등록할 때 options 인수에 추가 입력 또는 출력을 지정할 수 있습니다. @azure/functions 모듈에서 내보낸 inputoutput 개체는 구문을 구성하는 데 도움이 되는 형식별 메서드를 제공합니다. 실행 중에 context.extraInputs.get 또는 context.extraOutputs.set를 사용하여 값을 가져오거나 설정하고 원래 구성 개체를 첫 번째 인수로 전달합니다.

다음 예는 추가 스토리지 Blob 출력에 복사되는 추가 스토리지 Blob 입력이 있는 스토리지 큐에 의해 트리거되는 함수입니다. 큐 메시지는 파일 이름이어야 하며 바인딩 식을 사용하여 복사할 Blob 이름으로 {queueTrigger}를 대체합니다.

const { app, input, output } = require('@azure/functions');

const blobInput = input.storageBlob({
    connection: 'storage_APPSETTING',
    path: 'helloworld/{queueTrigger}',
});

const blobOutput = output.storageBlob({
    connection: 'storage_APPSETTING',
    path: 'helloworld/{queueTrigger}-copy',
});

app.storageQueue('copyBlob1', {
    queueName: 'copyblobqueue',
    connection: 'storage_APPSETTING',
    extraInputs: [blobInput],
    extraOutputs: [blobOutput],
    handler: (queueItem, context) => {
        const blobInputValue = context.extraInputs.get(blobInput);
        context.extraOutputs.set(blobOutput, blobInputValue);
    }
});

제네릭 입력 및 출력

@azure/functions 모듈에서 내보낸 app, trigger, inputoutput 개체는 대부분의 형식에 대해 형식별 메서드를 제공합니다. 지원되지 않는 모든 형식의 경우 구성을 수동으로 지정할 수 있도록 generic 메서드가 제공됩니다. 형식별 메서드에서 제공하는 기본 설정을 변경하려는 경우에도 generic 메서드를 사용할 수 있습니다.

다음 예는 형식별 메서드 대신 제네릭 메서드를 사용하는 간단한 HTTP 트리거 함수입니다.

const { app, output, trigger } = require('@azure/functions');

app.generic('helloWorld1', {
    trigger: trigger.generic({
        type: 'httpTrigger',
        methods: ['GET', 'POST']
    }),
    return: output.generic({
        type: 'http'
    }),
    handler: async (request, context) => {
        context.log(`Http function processed request for url "${request.url}"`);

        return { body: `Hello, world!` };
    }
});

호출 컨텍스트

함수의 각 호출은 입력을 읽고, 출력을 설정하고, 로그에 쓰고, 다양한 메타데이터를 읽는 데 사용되는 호출 context 개체를 전달합니다. v3 모델에서 컨텍스트 개체는 항상 처리기에 전달되는 첫 번째 인수입니다.

context 개체의 속성은 다음과 같습니다.

속성 설명
invocationId 현재 함수 호출의 ID입니다.
executionContext 실행 컨텍스트를 참조하세요.
bindings 바인딩을 참조하세요.
bindingData 값 자체를 포함하지 않고 이 호출에 대한 트리거 입력에 대한 메타데이터입니다. 예를 들어 이벤트 허브 트리거에는 enqueuedTimeUtc 속성이 있습니다.
traceContext 분산 추적에 대한 컨텍스트입니다. 자세한 내용은 Trace Context를 참조하세요.
bindingDefinitions function.json에 정의된 입력 및 출력의 구성입니다.
req HTTP 요청을 참조하세요.
res HTTP 응답을 참조하세요.

context.executionContext

context.executionContext 개체의 속성은 다음과 같습니다.

속성 설명
invocationId 현재 함수 호출의 ID입니다.
functionName 호출되는 함수의 이름입니다. function.json 파일이 포함된 폴더의 이름에 따라 함수 이름이 결정됩니다.
functionDirectory function.json 파일이 포함된 폴더입니다.
retryContext 다시 시도 컨텍스트를 참조하세요.

context.executionContext.retryContext

context.executionContext.retryContext 개체의 속성은 다음과 같습니다.

속성 설명
retryCount 현재 재시도 시도를 나타내는 숫자입니다.
maxRetryCount 실행이 다시 시도되는 최대 횟수입니다. -1 값은 무기한으로 다시 시도하는 것을 의미합니다.
exception 다시 시도를 발생시킨 예외입니다.

context.bindings

context.bindings 개체는 입력을 읽거나 출력을 설정하는 데 사용됩니다. 다음 예제는 context.bindings를 사용하여 스토리지 Blob 입력스토리지 Blob 출력으로 복사하는 스토리지 큐 트리거입니다. 큐 메시지의 콘텐츠는 {queueTrigger}바인딩 식을 사용하여 복사할 파일 이름으로 을 대체합니다.

{
    "name": "myQueueItem",
    "type": "queueTrigger",
    "direction": "in",
    "connection": "storage_APPSETTING",
    "queueName": "helloworldqueue"
},
{
    "name": "myInput",
    "type": "blob",
    "direction": "in",
    "connection": "storage_APPSETTING",
    "path": "helloworld/{queueTrigger}"
},
{
    "name": "myOutput",
    "type": "blob",
    "direction": "out",
    "connection": "storage_APPSETTING",
    "path": "helloworld/{queueTrigger}-copy"
}
module.exports = async function (context, myQueueItem) {
    const blobValue = context.bindings.myInput;
    context.bindings.myOutput = blobValue;
};

context.done

context.done 메서드는 더 이상 사용되지 않습니다. 비동기 함수가 지원되기 전에 context.done()을 호출하여 함수가 완료되었음을 알립니다.

module.exports = function (context, request) {
    context.log("this pattern is now deprecated");
    context.done();
};

이제 context.done()에 대한 호출을 제거하고 함수를 비동기로 표시하여 프라미스를 반환하는 것이 좋습니다(await를 수행하지 않는 경우라도). 함수가 완료되는 즉시(즉, 반환된 프라미스가 확인됨) v3 모델은 함수가 완료된 것을 알 수 있습니다.

module.exports = async function (context, request) {
    context.log("you don't need context.done or an awaited call")
};

함수의 각 호출에는 로깅에 사용되는 호출 및 메서드에 대한 정보가 포함된 호출 context 개체가 전달됩니다. v4 모델에서 context 개체는 일반적으로 처리기에 전달되는 두 번째 인수입니다.

InvocationContext 클래스에는 다음 속성이 있습니다.

속성 설명
invocationId 현재 함수 호출의 ID입니다.
functionName 함수의 이름.
extraInputs 추가 입력 값을 가져오는 데 사용됩니다. 자세한 내용은 추가 입력 및 출력을 참조하세요.
extraOutputs 추가 출력 값을 설정할 때 사용합니다. 자세한 내용은 추가 입력 및 출력을 참조하세요.
retryContext 다시 시도 컨텍스트를 참조하세요.
traceContext 분산 추적에 대한 컨텍스트입니다. 자세한 내용은 Trace Context를 참조하세요.
triggerMetadata 값 자체를 포함하지 않고 이 호출에 대한 트리거 입력에 대한 메타데이터입니다. 예를 들어 이벤트 허브 트리거에는 enqueuedTimeUtc 속성이 있습니다.
options 유효성을 검사하고 기본값을 명시적으로 지정한 후 함수를 등록할 때 사용되는 옵션입니다.

다시 시도 컨텍스트

retryContext 개체의 속성은 다음과 같습니다.

속성 설명
retryCount 현재 재시도 시도를 나타내는 숫자입니다.
maxRetryCount 실행이 다시 시도되는 최대 횟수입니다. -1 값은 무기한으로 다시 시도하는 것을 의미합니다.
exception 다시 시도를 발생시킨 예외입니다.

자세한 내용은 retry-policies를 참조하세요.

로깅

Azure Functions에서 context.log()를 사용하여 로그를 작성하는 것이 좋습니다. Azure Functions는 Azure Application Insights와 통합되어 함수 앱 로그를 더 잘 캡처합니다. Azure Monitor의 일부인 Application Insights는 애플리케이션 로그와 추적 출력을 모두 수집하고, 시각적으로 렌더링하고, 분석하는 기능을 제공합니다. 자세한 내용은 Azure Functions 모니터링을 참조하세요.

참고 항목

대체 Node.js console.log 메서드를 사용하는 경우 해당 로그는 앱 수준에서 추적되며 특정 함수와 연결되지 않습니다. 모든 로그가 특정 함수와 연결되도록 console 대신 로깅에 context를 사용하는 것이 적극 권장됩니다.

다음 예에서는 호출 ID를 포함하여 기존 "정보 수준"에서 로그를 작성합니다.

context.log(`Something has happened. Invocation ID: "${context.invocationId}"`);

로그 수준

기본 context.log 메서드 외에도 특정 수준에서 로그를 작성할 수 있는 다음 메서드를 사용할 수 있습니다.

메서드 설명
context.log.error() 로그에 오류 수준 이벤트를 씁니다.
context.log.warn() 로그에 경고 수준 이벤트를 씁니다.
context.log.info() 정보 수준 이벤트를 로그에 로그합니다.
context.log.verbose() 추적 수준 이벤트를 로그에 로그합니다.
메서드 설명
context.trace() 추적 수준 이벤트를 로그에 로그합니다.
context.debug() 로그에 디버그 수준 이벤트를 씁니다.
context.info() 정보 수준 이벤트를 로그에 로그합니다.
context.warn() 로그에 경고 수준 이벤트를 씁니다.
context.error() 로그에 오류 수준 이벤트를 씁니다.

로그 수준 구성

Azure Functions를 사용하면 로그를 추적하고 볼 때 사용할 임계값 수준을 정의할 수 있습니다. 임계값을 설정하려면 host.json 파일의 logging.logLevel 속성을 사용합니다. 이 속성을 사용하면 모든 함수에 적용되는 기본 수준 또는 각 개별 함수에 대한 임계값을 정의할 수 있습니다. 자세한 내용은 Azure Functions에 대한 모니터링을 구성하는 방법을 참조하세요.

사용자 지정 데이터 추적

기본적으로 Azure Functions는 Application Insights에 대한 추적으로 출력을 씁니다. 더 많은 제어를 위해 대신 Application Insights Node.js SDK를 사용하여 Application Insights 인스턴스에 사용자 지정 데이터를 보낼 수 있습니다.

const appInsights = require("applicationinsights");
appInsights.setup();
const client = appInsights.defaultClient;

module.exports = async function (context, request) {
    // Use this with 'tagOverrides' to correlate custom logs to the parent function invocation.
    var operationIdOverride = {"ai.operation.id":context.traceContext.traceparent};

    client.trackEvent({name: "my custom event", tagOverrides:operationIdOverride, properties: {customProperty2: "custom property value"}});
    client.trackException({exception: new Error("handled exceptions can be logged with this method"), tagOverrides:operationIdOverride});
    client.trackMetric({name: "custom metric", value: 3, tagOverrides:operationIdOverride});
    client.trackTrace({message: "trace message", tagOverrides:operationIdOverride});
    client.trackDependency({target:"http://dbname", name:"select customers proc", data:"SELECT * FROM Customers", duration:231, resultCode:0, success: true, dependencyTypeName: "ZSQL", tagOverrides:operationIdOverride});
    client.trackRequest({name:"GET /customers", url:"http://myserver/customers", duration:309, resultCode:200, success:true, tagOverrides:operationIdOverride});
};

tagOverrides 매개 변수는 operation_Id를 함수의 호출 ID로 설정합니다. 이 설정을 사용하면 지정된 함수 호출에 대해 자동으로 생성된 모든 로그와 사용자 지정 로그를 연관시킬 수 있습니다.

HTTP 트리거

HTTP 및 웹후크 트리거는 요청 및 응답 개체를 사용하여 HTTP 메시지를 나타냅니다.

HTTP 및 웹후크 트리거는 HttpRequestHttpResponse 개체를 사용하여 HTTP 메시지를 나타냅니다. 클래스는 Node.js의 undici 패키지를 사용하여 페치 표준의 하위 집합을 나타냅니다.

HTTP 요청

요청은 다음과 같은 여러 가지 방법으로 액세스할 수 있습니다.

  • 함수의 두 번째 인수로:

    module.exports = async function (context, request) {
        context.log(`Http function processed request for url "${request.url}"`);
    
  • context.req 속성에서:

    module.exports = async function (context, request) {
        context.log(`Http function processed request for url "${context.req.url}"`);
    
  • 명명된 입력 바인딩에서: 이 옵션은 HTTP가 아닌 바인딩과 동일하게 작동합니다. function.json의 바인딩 이름은 context.bindings의 키 또는 다음 예제의 "request1"과 일치해야 합니다.

    {
        "name": "request1",
        "type": "httpTrigger",
        "direction": "in",
        "authLevel": "anonymous",
        "methods": [
            "get",
            "post"
        ]
    }
    
    module.exports = async function (context, request) {
        context.log(`Http function processed request for url "${context.bindings.request1.url}"`);
    

HttpRequest 개체의 속성은 다음과 같습니다.

속성 Type 설명
method string 이 함수를 호출하는 데 사용되는 HTTP 요청 메서드입니다.
url string 요청 URL.
headers Record<string, string> HTTP 요청 헤더. 이 개체는 대/소문자를 구분합니다. 대신 대/소문자를 구분하지 않는 request.getHeader('header-name')을 사용하는 것이 좋습니다.
query Record<string, string> URL에서 문자열 매개 변수 키 및 값을 쿼리합니다.
params Record<string, string> 매개 변수 키 및 값을 라우팅합니다.
user HttpRequestUser | null 함수 인증, SWA 인증 또는 로그인한 사용자가 없는 경우 null을 통해 로그인한 사용자를 나타내는 개체입니다.
body Buffer | string | any 미디어 형식이 "application/octet-stream" 또는 "multipart/*"인 경우 body는 Buffer입니다. 값이 JSON 구문 분석 가능 문자열인 경우 body는 구문 분석된 개체입니다. 그렇지 않으면 body가 문자열입니다.
rawBody string 문자열 본문입니다. 이름과 달리, 이 속성은 버퍼를 반환하지 않습니다.
bufferBody Buffer 버퍼로서의 본문입니다.

요청은 HTTP 트리거 함수에 대한 처리기의 첫 번째 인수로 액세스할 수 있습니다.

async (request, context) => {
    context.log(`Http function processed request for url "${request.url}"`);

HttpRequest 개체의 속성은 다음과 같습니다.

속성 Type 설명
method string 이 함수를 호출하는 데 사용되는 HTTP 요청 메서드입니다.
url string 요청 URL.
headers Headers HTTP 요청 헤더.
query URLSearchParams URL에서 문자열 매개 변수 키 및 값을 쿼리합니다.
params Record<string, string> 매개 변수 키 및 값을 라우팅합니다.
user HttpRequestUser | null 함수 인증, SWA 인증 또는 로그인한 사용자가 없는 경우 null을 통해 로그인한 사용자를 나타내는 개체입니다.
body ReadableStream | null 읽기 가능한 스트림으로서의 본문입니다.
bodyUsed boolean 본문을 이미 읽었는지 여부를 나타내는 부울입니다.

요청 또는 응답의 본문에 액세스하려면 다음 방법을 사용할 수 있습니다.

메서드 반환 형식
arrayBuffer() Promise<ArrayBuffer>
blob() Promise<Blob>
formData() Promise<FormData>
json() Promise<unknown>
text() Promise<string>

참고 항목

본문 함수는 한 번만 실행할 수 있습니다. 후속 호출은 빈 문자열/ArrayBuffers로 해결됩니다.

HTTP 응답

응답은 다음과 같은 여러 가지 방법으로 설정할 수 있습니다.

  • context.res 속성을 설정합니다.

    module.exports = async function (context, request) {
        context.res = { body: `Hello, world!` };
    
  • 응답 반환: 함수가 비동기이고 바인딩 이름을 $return에서 function.json으로 설정한 경우 context에서 설정하는 대신 응답을 직접 반환할 수 있습니다.

    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
    
    module.exports = async function (context, request) {
        return { body: `Hello, world!` };
    
  • 명명된 입력 바인딩 설정: 이 옵션은 HTTP가 아닌 바인딩과 동일하게 작동합니다. function.json의 바인딩 이름은 context.bindings의 키 또는 다음 예제의 "response1"과 일치해야 합니다.

    {
        "type": "http",
        "direction": "out",
        "name": "response1"
    }
    
    module.exports = async function (context, request) {
        context.bindings.response1 = { body: `Hello, world!` };
    
  • context.res.send() 호출: 이 옵션은 사용되지 않습니다. 암시적으로 context.done()을 호출하며 비동기 함수에서 사용할 수 없습니다.

    module.exports = function (context, request) {
        context.res.send(`Hello, world!`);
    

응답을 설정할 때 새 개체를 만드는 경우 해당 개체는 다음 속성이 있는 HttpResponseSimple 인터페이스와 일치해야 합니다.

속성 Type 설명
headers Record<string, string>(선택 사항) HTTP 응답 헤더.
cookies Cookie[](선택 사항) HTTP 응답 쿠키.
body any(선택 사항) HTTP 응답 본문.
statusCode number(선택 사항) HTTP 응답 상태 코드입니다. 설정하지 않으면 기본값은 200입니다.
status number(선택 사항) statusCode와 동일합니다. statusCode가 설정된 경우 이 속성은 무시됩니다.

context.res 개체를 덮어쓰지 않고 수정할 수도 있습니다. 기본 context.res 개체는 HttpResponseSimple 속성 외에도 다음 메서드를 지원하는 HttpResponseFull 인터페이스를 사용합니다.

메서드 설명
status() 상태를 설정합니다.
setHeader() 헤더 필드를 설정합니다. 참고: res.set()res.header()도 지원되며 동일한 작업을 수행합니다.
getHeader() 헤더 필드를 가져옵니다. 참고: res.get()도 지원되며 동일한 작업을 수행합니다.
removeHeader() 헤더를 제거합니다.
type() "content-type" 헤더를 설정합니다.
send() 이 메서드는 더 이상 사용되지 않습니다. 본문을 설정하고 context.done()을 호출하여 동기화 함수가 완료되었음을 나타냅니다. 참고: res.end()도 지원되며 동일한 작업을 수행합니다.
sendStatus() 이 메서드는 더 이상 사용되지 않습니다. 상태 코드를 설정하고 context.done()을 호출하여 동기화 함수가 완료되었음을 나타냅니다.
json() 이 메서드는 더 이상 사용되지 않습니다. "content-type"을 "application/json"으로 설정하고, 본문을 설정하고, context.done()을 호출하여 동기화 함수가 완료되었음을 나타냅니다.

응답은 다음과 같은 여러 가지 방법으로 설정할 수 있습니다.

  • HttpResponseInit 형식의 간단한 인터페이스: 이 옵션은 응답을 반환하는 가장 간결한 방법입니다.

    return { body: `Hello, world!` };
    

    HttpResponseInit 인터페이스에는 다음과 같은 속성이 있습니다.

    속성 Type 설명
    body BodyInit(선택 사항) ArrayBuffer, AsyncIterable<Uint8Array>, Blob, FormData, Iterable<Uint8Array>, NodeJS.ArrayBufferView, URLSearchParams, null 또는 string 중 하나인 HTTP 응답 본문.
    jsonBody any(선택 사항) JSON 직렬화 가능한 HTTP 응답 본문. 설정한 경우 이 속성을 위해 HttpResponseInit.body 속성이 무시됩니다.
    status number(선택 사항) HTTP 응답 상태 코드입니다. 설정하지 않으면 기본값은 200입니다.
    headers HeadersInit(선택 사항) HTTP 응답 헤더.
    cookies Cookie[](선택 사항) HTTP 응답 쿠키.
  • HttpResponse 형식의 클래스로: 이 옵션은 헤더와 같은 응답의 다양한 부분을 읽고 수정하기 위한 도우미 메서드를 제공합니다.

    const response = new HttpResponse({ body: `Hello, world!` });
    response.headers.set('content-type', 'application/json');
    return response;
    

    HttpResponse 클래스는 선택적 HttpResponseInit를 생성자에 대한 인수로 허용하며 다음과 같은 속성을 가집니다.

    속성 Type 설명
    status number HTTP 응답 상태 코드입니다.
    headers Headers HTTP 응답 헤더.
    cookies Cookie[] HTTP 응답 쿠키.
    body ReadableStream | null 읽기 가능한 스트림으로서의 본문입니다.
    bodyUsed boolean 본문을 이미 읽었는지 여부를 나타내는 부울입니다.

HTTP 스트림

HTTP 스트림은 대용량 데이터 처리, OpenAI 응답 스트리밍, 동적 콘텐츠 제공 및 기타 핵심 HTTP 시나리오 지원을 더 쉽도록 하는 기능입니다. Node.js 함수 앱의 HTTP 엔드포인트에 대한 요청과 응답을 스트리밍할 수 있습니다. 앱에 HTTP를 통한 클라이언트와 서버 간의 실시간 교환 및 상호 작용이 필요한 시나리오에서 HTTP 스트림을 사용합니다. HTTP 스트림을 사용하면 HTTP를 사용할 때 앱에 대한 최고의 성능과 안정성을 가져올 수도 있습니다.

Important

v3 모델에서는 HTTP 스트림이 지원되지 않습니다. HTTP 스트리밍 기능을 사용하려면 v4 모델로 업그레이드합니다.

프로그래밍 모델 v4의 기존 HttpRequestHttpResponse 형식은 스트림을 포함하여 메시지 본문을 처리하는 다양한 방법을 이미 지원합니다.

필수 조건

스트림 사용

Azure의 함수 앱과 로컬 프로젝트에서 HTTP 스트림을 사용하도록 설정하려면 다음 단계를 사용합니다.

  1. 대량의 데이터를 스트리밍하려는 경우 Azure에서 FUNCTIONS_REQUEST_BODY_SIZE_LIMIT 설정을 수정합니다. 허용되는 기본 최대 본문 크기는 104857600이며, 이는 요청 크기를 ~100MB로 제한합니다.

  2. 로컬 개발의 경우 local.settings.json 파일FUNCTIONS_REQUEST_BODY_SIZE_LIMIT도 추가합니다.

  3. 기본 필드에 포함된 파일의 앱에 다음 코드를 추가합니다.

    const { app } = require('@azure/functions'); 
    
    app.setup({ enableHttpStream: true });
    

스트림 예제

이 예에서는 HTTP POST 요청을 통해 데이터를 수신하는 HTTP 트리거 함수와 함수가 이 데이터를 지정된 출력 파일로 스트리밍하는 것을 보여 줍니다.

const { app } = require('@azure/functions');
const { createWriteStream } = require('fs');
const { Writable } = require('stream');

app.http('httpTriggerStreamRequest', {
    methods: ['POST'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        const writeStream = createWriteStream('<output file path>');
        await request.body.pipeTo(Writable.toWeb(writeStream));

        return { body: 'Done!' };
    },
});

이 예에서는 수신되는 HTTP GET 요청에 대한 응답으로 파일 콘텐츠를 스트리밍하는 HTTP 트리거 함수를 보여 줍니다.

const { app } = require('@azure/functions');
const { createReadStream } = require('fs');

app.http('httpTriggerStreamResponse', {
    methods: ['GET'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        const body = createReadStream('<input file path>');

        return { body };
    },
});

스트림을 사용하여 즉시 실행 가능한 샘플 앱을 보려면 GitHub에서 이 예를 확인합니다.

스트림 고려 사항

  • 스트림 사용으로 최대의 이점을 가져오려면 request.body를 사용합니다. 본문을 항상 문자열로 반환하는 request.text()와 같은 메서드를 계속 사용할 수 있습니다.

후크

후크는 v3 모델에서 지원되지 않습니다. 후크를 사용하도록 v4 모델로 업그레이드합니다.

후크를 사용하여 Azure Functions 수명 주기의 여러 지점에서 코드를 실행합니다. 후크는 등록된 순서대로 실행되며 앱의 모든 파일에서 등록할 수 있습니다. 현재 후크의 범위는 "앱" 수준과 "호출" 수준의 두 가지입니다.

할당 후크

호출 후크는 함수 호출에 따라 preInvocation 후크 이전에 또는 postInvocation 후크 이후에 한 번 실행됩니다. 기본적으로 후크는 모든 트리거 형식에 대해 실행되지만 형식별로 필터링할 수도 있습니다. 다음 예제에서는 호출 후크를 등록하고 트리거 유형별로 필터링하는 방법을 보여 줍니다.

const { app } = require('@azure/functions');

app.hook.preInvocation((context) => {
    if (context.invocationContext.options.trigger.type === 'httpTrigger') {
        context.invocationContext.log(
            `preInvocation hook executed for http function ${context.invocationContext.functionName}`
        );
    }
});

app.hook.postInvocation((context) => {
    if (context.invocationContext.options.trigger.type === 'httpTrigger') {
        context.invocationContext.log(
            `postInvocation hook executed for http function ${context.invocationContext.functionName}`
        );
    }
});

후크 처리기에 대한 첫 번째 인수는 해당 후크 형식과 관련된 컨텍스트 개체입니다.

PreInvocationContext 개체의 속성은 다음과 같습니다.

속성 설명
inputs 호출에 전달된 인수입니다.
functionHandler 호출에 대한 함수 처리기입니다. 이 값을 변경하면 함수 자체에 영향을 미칩니다.
invocationContext 함수에 전달된 호출 컨텍스트 개체입니다.
hookData 동일한 범위의 후크 간에 데이터를 저장하고 공유하는 데 권장되는 위치입니다. 다른 후크의 데이터와 충돌하지 않도록 고유한 속성 이름을 사용해야 합니다.

PostInvocationContext 개체의 속성은 다음과 같습니다.

속성 설명
inputs 호출에 전달된 인수입니다.
result 함수의 결과입니다. 이 값을 변경하면 함수의 전체 결과에 영향을 미칩니다.
error 함수에서 throw된 오류이거나, 오류가 없으면 null/undefined입니다. 이 값을 변경하면 함수의 전체 결과에 영향을 미칩니다.
invocationContext 함수에 전달된 호출 컨텍스트 개체입니다.
hookData 동일한 범위의 후크 간에 데이터를 저장하고 공유하는 데 권장되는 위치입니다. 다른 후크의 데이터와 충돌하지 않도록 고유한 속성 이름을 사용해야 합니다.

앱 후크

앱 후크는 appStart 후크에서 시작하는 동안 또는 appTerminate 후크에서 종료하는 동안 앱 인스턴스당 한 번씩 실행됩니다. 앱 종료 후크는 실행 시간이 제한되어 있으며 모든 시나리오에서 실행되지는 않습니다.

Azure Functions 런타임은 현재 호출 외부의 컨텍스트 로깅을 지원하지 않습니다. Application Insights npm 패키지를 사용하여 앱 수준 후크 중에 데이터를 기록합니다.

다음 예에서는 앱 후크를 등록합니다.

const { app } = require('@azure/functions');

app.hook.appStart((context) => {
    // add your logic here
});

app.hook.appTerminate((context) => {
    // add your logic here
});

후크 처리기에 대한 첫 번째 인수는 해당 후크 형식과 관련된 컨텍스트 개체입니다.

AppStartContext 개체의 속성은 다음과 같습니다.

속성 설명
hookData 동일한 범위의 후크 간에 데이터를 저장하고 공유하는 데 권장되는 위치입니다. 다른 후크의 데이터와 충돌하지 않도록 고유한 속성 이름을 사용해야 합니다.

AppTerminateContext 개체의 속성은 다음과 같습니다.

속성 설명
hookData 동일한 범위의 후크 간에 데이터를 저장하고 공유하는 데 권장되는 위치입니다. 다른 후크의 데이터와 충돌하지 않도록 고유한 속성 이름을 사용해야 합니다.

스케일링 및 동시성

기본적으로 Azure Functions는 애플리케이션의 부하를 자동으로 모니터링하면서 필요에 따라 Node.js에 사용할 추가 호스트 인스턴스를 만듭니다. Azure Functions는 QueueTrigger에 대한 메시지 보존 기간, 큐 크기 등의 기본 제공(사용자 구성 불가능) 임계값을 여러 트리거 유형에 사용하여 인스턴스를 추가할 시기를 결정합니다. 자세한 내용은 사용 계획 및 프리미엄 계획의 작동 방식을 참조하세요.

해당 스케일링 동작은 여러 Node.js 애플리케이션을 지원하기에 충분합니다. CPU에 바인딩된 애플리케이션의 경우 여러 언어 작업자 프로세스를 사용하여 성능을 향상시킬 수 있습니다. FUNCTIONS_WORKER_PROCESS_COUNT 애플리케이션 설정을 사용하여 호스트당 작업자 프로세스 수를 기본값 1에서 최대 10개까지 늘릴 수 있습니다. 그러면 Azure Functions는 이러한 작업자 사이에 동시 함수 호출을 균등하게 분산하려고 시도합니다. 이 동작은 CPU를 많이 사용하는 함수가 다른 함수의 실행을 차단할 가능성을 줄입니다. 이 설정은 수요를 충족하기 위해 애플리케이션의 크기를 조정할 때 Azure Functions가 만드는 각 호스트에 적용됩니다.

Warning

FUNCTIONS_WORKER_PROCESS_COUNT 설정을 사용할 때는 주의해야 합니다. 동일한 인스턴스에서 실행되는 여러 프로세스는 예측할 수 없는 동작을 유발하고 함수 로드 시간을 증가시킬 수 있습니다. 이 설정을 사용하는 경우 패키지 파일에서 실행하여 이러한 단점을 상쇄하는 것이 좋습니다.

노드 버전

함수에서 process.version을 로깅하여 해당 런타임이 사용하는 현재 버전을 볼 수 있습니다. 각 프로그래밍 모델에서 지원하는 Node.js 버전 목록은 supported versions를 참조하세요.

노드 버전 설정

Node.js 버전을 업그레이드하는 방법은 함수 앱이 실행되는 OS에 따라 달라집니다.

Windows에서 실행하는 경우 Node.js 버전은 WEBSITE_NODE_DEFAULT_VERSION 애플리케이션 설정에 따라 설정됩니다. 이 설정은 Azure CLI를 사용하거나 Azure Portal에서 업데이트할 수 있습니다.

Node.js 버전에 대한 자세한 내용은 지원되는 버전을 참조하세요.

Node.js 버전을 업그레이드하기 전에 함수 앱이 최신 버전의 Azure Functions 런타임에서 실행되고 있는지 확인합니다. 런타임 버전을 업그레이드해야 하는 경우 Azure Functions 버전 3.x에서 버전 4.x로 앱 마이그레이션을 참조하세요.

Azure CLI az functionapp config appsettings set 명령을 실행하여 Windows에서 실행되는 함수 앱의 Node.js 버전을 업데이트합니다.

az functionapp config appsettings set  --settings WEBSITE_NODE_DEFAULT_VERSION=~20 \
 --name <FUNCTION_APP_NAME> --resource-group <RESOURCE_GROUP_NAME> 

그러면 지원되는 ~20의 LTS 버전이 WEBSITE_NODE_DEFAULT_VERSION 애플리케이션 설정으로 설정됩니다.

변경한 후 함수 앱이 다시 시작됩니다. Node.js에 대한 Functions 지원에 대해 자세히 알아보려면 언어 런타임 지원 정책을 참조하세요.

환경 변수

환경 변수는 운영 비밀(연결 문자열, 키, 엔드포인트 등) 또는 프로파일링 변수와 같은 환경 설정에 유용할 수 있습니다. 로컬 및 클라우드 환경 모두에 환경 변수를 추가하고 함수 코드에서 process.env를 통해 액세스할 수 있습니다.

다음 예제에서는 WEBSITE_SITE_NAME 환경 변수를 기록합니다.

module.exports = async function (context) {
    context.log(`WEBSITE_SITE_NAME: ${process.env["WEBSITE_SITE_NAME"]}`);
}
async function timerTrigger1(myTimer, context) {
    context.log(`WEBSITE_SITE_NAME: ${process.env["WEBSITE_SITE_NAME"]}`);
}

로컬 개발 환경

로컬에서 실행할 때 함수 프로젝트에는 환경 변수를 Values 개체에 저장하는 local.settings.json 파일이 포함됩니다.

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "CUSTOM_ENV_VAR_1": "hello",
    "CUSTOM_ENV_VAR_2": "world"
  }
}

Azure 클라우드 환경

Azure에서 실행하는 경우 함수 앱을 통해 서비스 연결 문자열과 같은 애플리케이션 설정을 사용 및 설정할 수 있고, 실행 중에 해당 설정을 환경 변수로 노출할 수 있습니다.

함수 앱 설정을 추가, 업데이트 및 삭제할 수 있는 여러 가지 방법이 있습니다.

함수 앱 설정을 변경하려면 함수 앱을 다시 시작해야 합니다.

작업자 환경 변수

Node.js와 관련된 몇 가지 Functions 환경 변수가 있습니다.

languageWorkers__node__arguments

이 설정을 사용하면 Node.js 프로세스를 시작할 때 사용자 지정 인수를 지정할 수 있습니다. 디버그 모드로 작업자를 시작하는 데 로컬로 가장 자주 사용되지만 사용자 지정 인수가 필요한 경우 Azure에서도 사용할 수 있습니다.

Warning

가능하면 콜드 시작 시간에 부정적인 영향을 미칠 수 있으므로 Azure에서 languageWorkers__node__arguments를 사용하지 마세요. 미리 준비된 작업자를 사용하는 대신 런타임은 사용자 지정 인수를 사용하여 새 작업자를 처음부터 시작해야 합니다.

logging__logLevel__Worker

이 설정은 Node.js 관련 작업자 로그의 기본 로그 수준을 조정합니다. 기본적으로 경고 또는 오류 로그만 표시되지만 information 또는 debug로 설정하여 Node.js 작업자 문제를 진단할 수 있습니다. 자세한 내용은 로그 수준 구성을 참조하세요.

ECMAScript 모듈(미리 보기)

참고 항목

ECMAScript 모듈은 현재 Azure Functions의 Node.js 14 이상에서 미리 보기 기능입니다.

ECMAScript 모듈(ES 모듈)은 Node.js에 대한 새로운 공식 표준 모듈 시스템입니다. 지금까지 이 문서의 코드 샘플에서는 CommonJS 구문을 사용합니다. Node.js 14 이상에서 Azure Functions를 실행하는 경우 ES 모듈 구문을 사용하여 함수를 작성하도록 선택할 수 있습니다.

함수에서 ES 모듈을 사용하려면 .mjs 확장을 사용하도록 파일 이름을 변경합니다. 다음 index.mjs 파일 예제는 ES 모듈 구문을 사용하여 uuid 라이브러리를 가져오고 값을 반환하는 HTTP 트리거 함수입니다.

import { v4 as uuidv4 } from 'uuid';

async function httpTrigger1(context, request) {
    context.res.body = uuidv4();
};

export default httpTrigger;
import { v4 as uuidv4 } from 'uuid';

async function httpTrigger1(request, context) {
    return { body: uuidv4() };
};

app.http('httpTrigger1', {
    methods: ['GET', 'POST'],
    handler: httpTrigger1
});

함수 진입점 구성

function.json 속성과 scriptFileentryPoint는 내보낸 함수의 위치와 이름을 구성하는 데 사용할 수 있습니다. scriptFile 속성은 TypeScript를 사용할 때 필요하며 컴파일된 JavaScript를 가리켜야 합니다.

scriptFile 사용

기본적으로 JavaScript 함수는 해당하는 function.json과 동일한 부모 디렉터리를 공유하는 index.js 파일에서 실행됩니다.

scriptFile은 다음 예제와 같은 폴더 구조를 가져오는 데 사용할 수 있습니다.

<project_root>/
 | - node_modules/
 | - myFirstFunction/
 | | - function.json
 | - lib/
 | | - sayHello.js
 | - host.json
 | - package.json

myFirstFunctionfunction.json에는 실행할 내보낸 함수가 있는 파일을 가리키는 scriptFile 속성이 포함되어야 합니다.

{
  "scriptFile": "../lib/sayHello.js",
  "bindings": [
    ...
  ]
}

entryPoint 사용

v3 모델에서 함수를 찾아서 실행하려면 module.exports를 사용하여 함수를 내보내야 합니다. 기본적으로 트리거되면 실행되는 함수는 해당 파일의 내보내기, run이라는 이름의 내보내기 또는 index라고 명명된 내보내기입니다. 다음 예제에서는 function.jsonentryPoint를 사용자 지정 값인 "logHello"로 설정합니다.

{
  "entryPoint": "logHello",
  "bindings": [
    ...
  ]
}
async function logHello(context) {
    context.log('Hello, world!');
}

module.exports = { logHello };

로컬 디버깅

디버그 모드에서 Node.js 프로세스를 자동으로 시작하고 프로세스에 연결하는 로컬 디버깅에는 VS Code를 사용하는 것이 좋습니다. 자세한 내용은 함수를 로컬로 실행을 참조하세요.

디버깅을 위해 다른 도구를 사용하거나 디버그 모드에서 Node.js 프로세스를 수동으로 시작하려는 경우 local.settings.jsonValues 아래에 "languageWorkers__node__arguments": "--inspect"를 추가합니다. --inspect 인수는 기본적으로 포트 9229에서 디버그 클라이언트를 수신 대기하도록 Node.js에게 지시합니다. 자세한 내용은 Node.js 디버깅 가이드를 참조하세요.

권장 사항

이 섹션에서는 따라야 하는 Node.js 앱에 대한 몇 가지 영향력 있는 패턴에 대해 설명합니다.

단일 vCPU App Service 계획 선택

App Service 계획을 사용하는 함수 앱을 만들 때 여러 vCPU가 있는 계획보다는 단일 vCPU 계획을 선택하는 것이 좋습니다. 현재 Functions는 단일 vCPU VM에서 Node.js 함수를 더 효율적으로 실행하며, 더 큰 VM을 사용해도 예상되는 성능 향상을 얻지 못합니다. 필요한 경우 더 많은 단일 vCPU VM 인스턴스를 추가하여 수동으로 스케일 아웃하거나 자동 스케일링을 사용하도록 설정할 수 있습니다. 자세한 내용은 수동 또는 자동으로 인스턴스 개수 조정을 참조하세요.

패키지 파일에서 실행

서버리스 호스팅 모델에서 Azure Functions를 개발하는 경우 사실상 콜드 부팅됩니다. 콜드 부팅은 함수 앱이 일정 시간 동안 작업하지 않은 후 처음으로 함수 앱을 시작하면 시작하는 데 더 오래 걸린다는 사실을 의미합니다. 특히 종속성 트리가 큰 Node.js 앱의 경우 콜드 스타트가 중요할 수 있습니다. 콜드 부팅 프로세스의 속도를 높이려면 가능한 경우 함수를 패키지 파일로 실행합니다. 많은 배포 방법이 기본적으로 이 모델을 사용하지만 대규모 콜드 부팅이 발생하는 경우 이 방식으로 실행되고 있는지 확인해야 합니다.

단일 정적 클라이언트 사용

Azure Functions 애플리케이션에서 서비스별 클라이언트를 사용하는 경우 연결 제한에 도달할 수 있으므로 모든 함수 호출에 새 클라이언트를 만들어서는 안 됩니다. 대신 전체 범위에서 단일 정적 클라이언트를 만듭니다. 자세한 내용은 Azure Functions에서 연결 관리를 참조하세요.

asyncawait 사용

Node.js로 Azure Functions를 작성하는 경우 asyncawait 키워드를 사용하여 코드를 작성해야 합니다. 콜백 대신 asyncawait를 사용하거나 프라미스와 함께 .then.catch를 사용하여 코드를 작성하면 다음 두 가지 일반적인 문제를 방지할 수 있습니다.

  • 잠재적으로 다른 함수 실행에 영향을 줄 수 있는 Node.js 프로세스 크래시를 유발하는 포착되지 않은 예외 발생
  • 올바르게 대기하지 않는 비동기 호출로 인해 context.log의 로그 누락과 같은 예기치 않은 동작이 발생합니다.

다음 예에서 비동기 메서드 fs.readFile은 오류 우선 콜백 함수를 두 번째 매개 변수로 사용하여 호출됩니다. 이 코드는 앞에서 언급한 두 가지 문제를 모두 일으킵니다. 올바른 범위에서 명시적으로 포착되지 않은 예외는 전체 프로세스를 중단시킬 수 있습니다.(문제 #1). 콜백이 완료되었는지 확인하지 않고 반환한다는 것은 http 응답에 빈 본문(문제 #2)이 있을 수 있다는 것입니다.

// DO NOT USE THIS CODE
const { app } = require('@azure/functions');
const fs = require('fs');

app.http('httpTriggerBadAsync', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        let fileData;
        fs.readFile('./helloWorld.txt', (err, data) => {
            if (err) {
                context.error(err);
                // BUG #1: This will result in an uncaught exception that crashes the entire process
                throw err;
            }
            fileData = data;
        });
        // BUG #2: fileData is not guaranteed to be set before the invocation ends
        return { body: fileData };
    },
});

다음 예에서 비동기 메서드 fs.readFile은 오류 우선 콜백 함수를 두 번째 매개 변수로 사용하여 호출됩니다. 이 코드는 앞에서 언급한 두 가지 문제를 모두 일으킵니다. 올바른 범위에서 명시적으로 포착되지 않은 예외는 전체 프로세스를 중단시킬 수 있습니다.(문제 #1). 콜백 범위를 벗어나 사용되지 않는 context.done() 메서드를 호출하면 파일을 읽기 전에 함수가 완료되었음을 알릴 수 있습니다(문제 #2). 이 예에서는 context.done()를 너무 일찍 호출하면 Data from file:로 시작하는 로그 항목이 누락됩니다.

// NOT RECOMMENDED PATTERN
const fs = require('fs');

module.exports = function (context) {
    fs.readFile('./hello.txt', (err, data) => {
        if (err) {
            context.log.error('ERROR', err);
            // BUG #1: This will result in an uncaught exception that crashes the entire process
            throw err;
        }
        context.log(`Data from file: ${data}`);
        // context.done() should be called here
    });
    // BUG #2: Data is not guaranteed to be read before the Azure Function's invocation ends
    context.done();
}

asyncawait 키워드를 사용하여 이러한 문제를 모두 방지할 수 있습니다. Node.js 에코시스템의 대부분의 API는 어떤 형태로든 프라미스를 지원하도록 변환되었습니다. 예를 들어 v14부터 Node.js는 fs 콜백 API를 대체하는 fs/promises API를 제공합니다.

다음 예제에서 함수 실행 중에 발생한 처리되지 않은 예외는 예외를 발생시킨 개별 호출에서만 실패합니다. await 키워드는 readFile 이후의 단계가 완료된 후에만 실행된다는 것을 의미합니다.

// Recommended pattern
const { app } = require('@azure/functions');
const fs = require('fs/promises');

app.http('httpTriggerGoodAsync', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        try {
            const fileData = await fs.readFile('./helloWorld.txt');
            return { body: fileData };
        } catch (err) {
            context.error(err);
            // This rethrown exception will only fail the individual invocation, instead of crashing the whole process
            throw err;
        }
    },
});

asyncawait를 사용하는 경우 context.done() 콜백도 호출할 필요가 없습니다.

// Recommended pattern
const fs = require('fs/promises');

module.exports = async function (context) {
    let data;
    try {
        data = await fs.readFile('./hello.txt');
    } catch (err) {
        context.log.error('ERROR', err);
        // This rethrown exception will be handled by the Functions Runtime and will only fail the individual invocation
        throw err;
    }
    context.log(`Data from file: ${data}`);
}

문제 해결

Node.js 문제 해결 가이드를 참조하세요.

다음 단계

자세한 내용은 다음 리소스를 참조하세요.