미들웨어Middleware

적용 대상: SDK v4APPLIES TO: SDK v4

미들웨어는 간단하게 말해서 어댑터와 봇 논리 사이에 위치하는 클래스로, 초기화하는 동안 어댑터의 미들웨어 컬렉션에 추가됩니다.Middleware is simply a class that sits between the adapter and your bot logic, added to your adapter's middleware collection during initialization. SDK를 사용하면 사용자 고유의 미들웨어를 작성하거나 다른 사람이 만든 미들웨어를 추가할 수 있습니다.The SDK allows you to write your own middleware or add middleware created by others. 봇으로 들어오거나 봇에서 나가는 모든 작업은 미들웨어를 통과합니다.Every activity coming into or out of your bot flows through your middleware.

어댑터는에서 봇 미들웨어 파이프라인을 통해 들어오는 활동을 처리 하 고이를 봇의 논리에 전달 하 고 다시 다시 보냅니다.The adapter processes and directs incoming activities in through the bot middleware pipeline to your bot's logic and then back out again. 각 작업이 봇으로 들어가고 나올 때 미들웨어의 각 부분은 봇 논리가 실행되기 전과 후에 작업을 검사하거나 작업에 따라 작동합니다.As each activity flows in and out of the bot, each piece of middleware can inspect or act upon the activity, both before and after the bot logic runs.

미들웨어를 살펴보기 전에, 먼저 봇의 일반론봇이 작업을 처리하는 방식을 이해해야 합니다.Before jumping into middleware, it is important to understand bots in general and how they process activities.

미들웨어 사용Uses for middleware

"작업은 일반 봇 논리를 사용하는 대신 미들웨어로 언제 구현해야 하나요?"라는 질문이 자주 제기됩니다.The question often comes up: "When should I implement actions as middleware versus using my normal bot logic?" 미들웨어는 대화가 처리되는 순서 의 전과 후에 사용자의 대화 흐름과 상호 작용하는 추가 기회를 제공합니다.Middleware provides you with additional opportunities to interact with your users' conversation flow both before and after each turn of the conversation is processed. 또한 미들웨어는 대화와 관련된 정보를 저장 및 검색하고 필요한 경우 추가 처리 논리를 호출할 수 있습니다.Middleware also allows you to store and retrieve information concerning the conversation and call additional processing logic when required. 아래는 미들웨어가 유용할 수 있는 일반적인 시나리오입니다.Below are some common scenarios that show where middleware can be useful.

모든 작업을 살펴보거나 모든 작업에 따라 작동Looking at or acting on every activity

봇이 모든 작업 또는 특정 유형의 모든 작업에 대해 무언가를 해야 하는 여러 상황이 있습니다.There are plenty of situations that require your bot to do something on every activity, or for every activity of a certain type. 예를 들어 봇이 수신하는 모든 메시지 작업을 기록하거나, 봇이 이 순서에 대한 응답을 생성하지 않으면 대체 응답을 제공하려는 경우가 있습니다.For example, you may want to log every message activity your bot receives or provide a fallback response if the bot has not otherwise generated a response this turn. 미들웨어는 나머지 봇 논리가 실행되기 전과 후에 작동하는 기능을 갖고 있기 때문에 이 시나리오를 구현하기에 매우 좋습니다.Middleware is a great place for this, with its ability to act both before and after the rest of the bot logic has executed.

턴 컨텍스트 수정 또는 개선Modifying or enhancing the turn context

작업에 제공되는 정보보다 더 많은 정보를 봇이 갖고 있으면 특정 대화가 훨씬 유익할 수 있습니다.Certain conversations can be much more fruitful if the bot has more information than what is provided in the activity. 이 경우 미들웨어는 지금까지의 대화 상태 정보를 살펴보고, 외부 데이터 원본을 쿼리하고, 턴 컨텍스트 개체에 추가한 후 봇 논리에 대한 실행을 전달할 수 있습니다.Middleware in this case could look at the conversation state information it has so far, query an external data source, and append that to the turn context object before passing execution on to the bot logic.

SDK는 들어오고 나가는 활동을 기록할 수 있는 로깅 미들웨어를 정의하지만, 사용자 고유의 미들웨어를 정의할 수도 있습니다.The SDK defines logging middleware that can record incoming and outgoing activities, but you can also define your own middleware.

봇 미들웨어 파이프라인The bot middleware pipeline

각 작업에 대해 어댑터는 미들웨어를 추가된 순서대로 호출합니다.For each activity, the adapter calls middleware in the order in which you added it. 어댑터는 턴 및 다음 대리자에 대한 컨텍스트 개체를 전달하고, 미들웨어는 파이프라인의 다음 미들웨어에 컨트롤을 전달할 대리자를 호출합니다.The adapter passes in the context object for the turn and a next delegate, and the middleware calls the delegate to pass control to the next middleware in the pipeline. 또한 미들웨어는 다음 대리자가 메서드를 반환한 후부터 완료하기 전까지 작업을 수행할 수 있는 기회가 있습니다.Middleware also has an opportunity to do things after the next delegate returns before completing the method. 각 미들웨어 개체에는 파이프라인에서 따르는 미들웨어 개체와 관련하여 작동할 수 있는 처음이자 마지막 기회가 있는 것으로 생각하셔도 좋습니다.You can think of it as each middleware object has the first-and-last chance to act with respect to the middleware objects that follow it in the pipeline.

다음은 그 예입니다.For example:

  • 첫 번째 미들웨어 개체의 턴 처리기는 다음 을 호출 하기 전에 코드를 실행 합니다.1st middleware object's turn handler executes code before calling next.
    • 두 번째 미들웨어 개체의 턴 처리기는 다음 을 호출 하기 전에 코드를 실행 합니다.2nd middleware object's turn handler executes code before calling next.
      • 봇의 턴 핸들러가를 실행 하 고를 반환 합니다.The bot's turn handler executes and returns.
    • 두 번째 미들웨어 개체의 턴 처리기는를 반환 하기 전에 나머지 코드를 실행 합니다.2nd middleware object's turn handler executes any remaining code before returning.
  • 첫 번째 미들웨어 개체의 턴 처리기는를 반환 하기 전에 나머지 코드를 실행 합니다.1st middleware object's turn handler executes any remaining code before returning.

미들웨어가 다음 대리자를 호출 하지 않는 경우 어댑터는 후속 미들웨어 나 봇 턴 처리기와 파이프라인 짧은 회로를 호출 하지 않습니다.If middleware doesn't call the next delegate, the adapter does not call any of the subsequent middleware or bot turn handlers, and the pipeline short circuits.

봇 미들웨어 파이프라인이 완료되면 턴이 끝나고, 턴 컨텍스트가 범위를 벗어납니다.Once the bot middleware pipeline completes, the turn is over, and the turn context goes out of scope.

미들웨어 또는 봇은 응답을 생성하고 응답 이벤트 처리기를 등록할 수 있지만, 응답이 별도의 프로세스에서 처리된다는 사실을 기억해야 합니다.Middleware or the bot can generate responses and register response event handlers, but keep in mind that responses are handled in separate processes.

미들웨어 순서Order of middleware

미들웨어가 추가되는 순서에 따라 미들웨어가 작업을 처리하는 순서가 결정되므로 미들웨어 추가 순서를 결정하는 것이 중요합니다.Since the order in which middleware is added determines the order in which the middleware processes an activity, it's important to decide the sequence that middleware should be added.

참고

이것은 대부분의 봇에서 작동하는 일반적인 패턴을 제공하기 위한 의도이지만, 미들웨어의 각 부분이 상황에 맞게 상호 작용하는 방식을 고려해야 합니다.This is meant to give you a common pattern that works for most bots, but be sure to consider how each piece of middleware will interact with the others for your situation.

미들웨어 파이프라인의 첫 번째 작업은 매번 사용되는 최하위 수준 작업을 처리하는 것일 확률이 높습니다.The first things in your middleware pipeline should likely be those that take care of the lowest-level tasks that are used every time. 로깅, 예외 처리, 변역을 예로 들 수 있습니다.Examples include logging, exception handling, and translation. 순서는 들어오는 메시지를 먼저 번역할 것인지, 메시지가 스토리지되기 전에 할 것인지 등의 요구 사항에 따라 달라질 수 있으며, 메시지 스토리지이 먼저 발생하는 경우 스토리지된 메시지가 번역되지 않을 수 있습니다.Ordering these can vary depending on your needs, such as whether you want the incoming message to be translated first, before messages are stored, or if message storage should occur first, which could mean stored messages wouldn't be translated.

미들웨어 파이프라인의 마지막은 봇 관련 미들웨어로, 봇으로 전송된 모든 메시지에 대한 처리 작업을 수행하도록 구현하는 미들웨어입니다.The last things in your middleware pipeline should be bot-specific middleware, which is middleware you implement to do some processing on every message sent to your bot. 미들웨어가 상태 정보 또는 봇 컨텍스트에 설정된 기타 정보를 사용하는 경우 상태 또는 컨텍스트를 수정하는 미들웨어 뒤에 있는 미들웨어 파이프라인에 해당 미들웨어를 추가합니다.If your middleware uses state information or other information set in the bot context, add it to the middleware pipeline after the middleware that modifies state or context.

단락Short circuiting

미들웨어 및 응답 처리기와 관련된 중요한 개념 중 하나는 단락 입니다.An important idea around middleware and response handlers is short circuiting. 이어지는 레이어를 통해 예외가 계속되는 경우 미들웨어(또는 응답 처리기)는 해당 다음 대리자를 호출하여 실행을 전달해야 합니다.If execution is to continue through the layers that follow it, middleware (or a response handler) is required to pass execution on by calling its next delegate. 해당 미들웨어(또는 응답 처리기) 내에서 다음 대리자를 호출하지 않으면 연결된 파이프라인이 단락되고 후속 레이어가 실행되지 않습니다.If the next delegate is not called within that middleware (or response handler), the associated pipeline short circuits and subsequent layers are not executed. 즉, 모든 봇 논리와 파이프라인에서 그 뒤에 있는 미들웨어를 건너뜁니다.This means all bot logic, and any middleware further along the pipeline, is skipped. 미들웨어와 응답 처리기의 순서 단락 간에는 미묘한 차이가 있습니다.There is a subtle difference between your middleware and your response handler short circuiting a turn.

미들웨어가 순서를 단락시키는 경우 봇 순서 처리기는 호출되지 않지만, 파이프라인에서 이 시점 전에 실행된 모든 미들웨어 코드는 완료될 때까지 계속 실행됩니다.When middleware short circuits a turn, your bot turn handler will not be called, but all middleware code executed prior to this point in the pipeline will still run to completion.

이벤트 처리기의 경우 다음 을 호출하지 않으면 이벤트가 취소되고, 미들웨어 건너뛰기 논리와 크게 다른 결과로 이어집니다.For event handlers, not calling next means that the event is cancelled, which is a significantly different result than middleware skipping logic. 어댑터는 이벤트의 나머지 부분을 처리하지 않음으로써 절대로 이벤트를 보내지 않습니다.By not processing the rest of the event, the adapter never sends it.

SendActivities처럼 응답 이벤트를 단락시키는 경우 본인이 의도한 동작이어야 합니다.If you do short-circuit a response event, such as SendActivities, be sure it's the behavior you intend. 그렇지 않으면 버그를 수정하기가 어려울 수 있습니다.Otherwise, it can result in difficult to fix bugs.

응답 이벤트 처리기Response event handlers

애플리케이션 및 미들웨어 논리 외에도, 컨텍스트 개체에 응답 처리기(이벤트 처리기 또는 작업 이벤트 처리기라고도 함)를 추가할 수 있습니다.In addition to the application and middleware logic, response handlers (also sometimes referred to as event handlers, or activity event handlers) can be added to the context object. 이러한 처리기는 현재 컨텍스트 개체에서 관련 응답이 발생하면 실제 응답을 실행하기 전에 호출됩니다.These handlers are called when the associated response happens on the current context object, before executing the actual response. 이러한 처리기는 실제 이벤트 전에 또는 후에 현재 응답의 나머지 부분에서 해당 형식의 모든 작업에 대해 무엇을 할 것인지 알고 있는 경우에 유용 합니다.These handlers are useful when you know you'll want to do something, either before or after the actual event, for every activity of that type for the rest of the current response.

경고

각 응답 이벤트 처리기 내부에서 해당 작업 응답 메서드를 호출하지 않도록 주의해야 합니다. 예를 들어 on send activity 처리기 내에서 send activity 메서드를 호출하면 안 됩니다.Be careful to not call an activity response method from within its respective response event handler, for example, calling the send activity method from within an on send activity handler. 호출하면 무한 루프가 생성될 수 있습니다.Doing so can generate an infinite loop.

새 작업마다 실행할 새 스레드가 생깁니다.Remember, each new activity gets a new thread to execute on. 작업을 처리하는 스레드가 생성되면 해당 작업에 대한 처리기 목록이 해당하는 새 스레드에 복사됩니다.When the thread to process the activity is created, the list of handlers for that activity is copied to that new thread. 해당 시점 이후 추가된 처리기는 해당 활동 이벤트에 대해 실행되지 않습니다.No handlers added after that point will be executed for that specific activity event. 컨텍스트 개체에 등록된 처리기는 어댑터에서 미들웨어 파이프라인을 관리하는 방법과 매우 비슷하게 처리됩니다.The handlers registered on a context object are handled very similarly to how the adapter manages the middleware pipeline. 즉, 처리기는 추가된 순서대로 호출되며, 다음 대리자를 호출하면 등록된 그 다음 이벤트 처리기에 컨트롤이 전달됩니다.Namely, handlers get called in the order they're added, and calling the next delegate passes control to the next registered event handler. 처리기에서 다음 대리자를 호출 하지 않는 경우에는 이벤트 짧은 회로와 어댑터는 응답을 채널에 보내지 않습니다.If a handler doesn't call the next delegate, none of the subsequent event handlers are called, the event short circuits, and the adapter does not send the response to the channel.

미들웨어의 상태 처리Handling state in middleware

상태를 저장하는 일반적인 방법은 턴 처리기의 끝에서 변경 내용 저장 메서드를 호출하는 것입니다.A common method to save state is to call the save changes method at the end of the turn handler. 호출에 초점을 맞춘 다이어그램은 다음과 같습니다.Here is a diagram with a focus on the call.

상태 미들웨어 문제

이 방법의 문제는 bot의 턴 처리기가 반환 된 후에 발생 하는 일부 사용자 지정 미들웨어에서 수행 된 모든 상태 업데이트는 영구 저장소에 저장 되지 않는 것입니다.The problem with this approach is that any state updates made from some custom middleware that happens after the bot's turn handler has returned will not be saved to durable storage. 해결 방법은 변경 내용 자동 저장 미들웨어의 인스턴스를 미들웨어 스택의 시작 부분에 추가하거나 적어도 상태를 업데이트할 수 있는 미들웨어 앞에 추가하여 사용자 지정 미들웨어가 완료된 후에 호출을 변경 내용 저장 메서드로 이동하는 것입니다.The solution is to move the call to the save changes method to after the custom middleware has completed by adding an instance of the auto-save changes middleware to the beginning of the middleware stack, or at least before any of the middleware that might update state. 실행은 아래와 같습니다.The execution is shown below.

상태 미들웨어 해결 방법

업데이트해야 하는 상태 관리 개체를 봇 상태 세트 개체에 추가한 다음, 변경 내용 자동 저장 미들웨어를 만들 때 이 개체를 사용합니다.Add the state management objects that will need updating to a bot state set object, and then use that when you create your auto-save changes middleware.

추가 리소스Additional resources

Bot Framework SDK [C# | JS]에 구현된 대본 로거 미들웨어를 살펴볼 수 있습니다.You can take a look at the transcript logger middleware, as implemented in the Bot Framework SDK [C# | JS].