Computer >> 컴퓨터 >  >> 프로그래밍 >> Redis

Upstash Redis, Next.js Server Actions 및 Vercel을 통한 실시간 알림:단계별 가이드

이 게시물에서는 Upstash Redis, Next.js Server Actions 및 Vercel과 함께 서버 전송 이벤트를 사용하여 실시간 알림을 구축한 방법에 대해 설명합니다. Upstash Redis의 메시지 채널을 활용하면 애플리케이션의 통신 아키텍처를 크게 향상시켜 반응성과 동성을 높일 수 있습니다.

데모

사용할 제품

  • Next.js(프런트엔드 및 백엔드)
  • Upstash Redis(PUBLISH 명령을 사용한 서버 전송 이벤트)
  • Tailwind CSS(스타일링)
  • Vercel(배포)

필요한 것

  • Node.js 18
  • Upstash 계정
  • Vercel 계정

Upstash Redis 설정

Upstash 계정을 생성하고 로그인하면 Redis 탭으로 이동하여 데이터베이스를 생성하게 됩니다.

Upstash Redis, Next.js Server Actions 및 Vercel을 통한 실시간 알림:단계별 가이드

Upstash Redis, Next.js Server Actions 및 Vercel을 통한 실시간 알림:단계별 가이드

데이터베이스를 생성한 후 세부정보 탭으로 이동합니다. 데이터베이스 연결 섹션을 찾을 때까지 아래로 스크롤합니다. Redis URL을 복사하여 안전한 곳에 저장하세요. UPSTASH_REDIS_URL로 사용하겠습니다. 환경 변수로 사용하세요.

Upstash Redis, Next.js Server Actions 및 Vercel을 통한 실시간 알림:단계별 가이드

또한 REST API 섹션을 찾을 때까지 아래로 스크롤하고 .env를 선택합니다. 버튼. 콘텐츠를 복사하여 안전한 곳에 저장하세요. UPSTASH_REDIS_REST_URL로 얻은 변수를 사용하겠습니다. 그리고 UPSTASH_REDIS_REST_TOKEN .

Upstash Redis, Next.js Server Actions 및 Vercel을 통한 실시간 알림:단계별 가이드

프로젝트 설정

설정하려면 앱 저장소를 복제하고 이 튜토리얼에 따라 그 안에 있는 모든 내용을 알아보세요. 프로젝트를 포크하려면 다음을 실행하세요:

git clone https://github.com/rishi-raj-jain/upstash-nextjs-publish-messages-with-sse-example
cd upstash-nextjs-publish-messages-with-sse-example
npm install

저장소를 복제한 후에는 .env 파일을 생성하게 됩니다. 위 섹션에서 저장한 항목을 추가하게 됩니다.

다음과 같아야 합니다:

# .env
 
# Obtained from the steps as above
 
# Upstash Redis Secrets
UPSTASH_REDIS_URL="rediss://default:...@...-...-...-....upstash.io:..."
UPSTASH_REDIS_REST_URL="https://...-...-...-....upstash.io"
UPSTASH_REDIS_REST_TOKEN="...="

UPSTASH_REDIS_URL에서 방법을 확인하세요. 변수에 "redis"가 아니라 "rediss"라고 되어 있는데, 이는 TLS/SSL 옵션을 사용한다는 의미입니다.

이 단계 후에는 다음 명령을 사용하여 로컬 환경을 시작할 수 있습니다:

npm run dev

저장소 구조

프로젝트의 메인 폴더 구조입니다. 이 게시물에서 다음 내용을 다루면서 더 자세히 논의할 파일을 빨간색으로 표시했습니다.

  • Upstash Redis의 메시지 채널 이해
  • Next.js 앱 라우터에서 서버 전송 이벤트 API 생성
  • Upstash Redis로 Next.js 서버 작업을 설정하여 알림 게시
  • Next.js 프런트엔드를 설정하여 실시간으로 알림을 지속적으로 수신하고 표시합니다.

Upstash Redis, Next.js Server Actions 및 Vercel을 통한 실시간 알림:단계별 가이드

Upstash Redis의 메시지 채널 이해

Upstash Redis에서 게시/구독 모델은 메시지 채널의 핵심입니다. 게시자는 지정된 채널에 메시지를 방송하고 구독자는 특정 채널에서 실시간으로 메시지를 받을 수 있습니다. 이 모델을 사용하면 애플리케이션의 여러 부분 간의 원활한 통신이 가능합니다.

Edge 호환 라이브러리 @upstash/redis를 사용하여 채널에 메시지를 게시하는 방법은 다음과 같습니다. 👇🏻

import { Redis } from '@upstash/redis'
 
// Connect to an Upstash Redis instance
const redis = Redis.fromEnv()
 
// Publish a message to the Upstash Redis instance
await redis.publish('posts', JSON.stringify({ date: new Date().toString(), message: "I am a new message." }))

구독자가 Upstash Redis 채널(여기서는 posts)을 들을 수 있는 방법은 다음과 같습니다. ) 노드 호환 라이브러리 ioredis 포함 👇🏻

// Use ioredis to be able to subscribe to an Upstash Redis instance
import Redis from 'ioredis'
 
// Create an Upstash Redis Subscriber instance
const redisSubscriber = new Redis(process.env.UPSTASH_REDIS_URL)
 
// Define the key to listen and publish messages to
const setKey = 'posts'
 
// Subscribe to Redis updates for the key: "posts"
// In case of any error, just log it
redisSubscriber.subscribe(setKey, (err) => {
 if (err) console.log(err)
})
 
// Listen for new posts from Redis
redisSubscriber.on('message', (channel, message) => {
 // Log the data when the channel message is received is same as the message is published to
 if (channel === setKey) console.log(mesage)
})

채널에 메시지를 게시하면 모든 구독자가 즉시 메시지를 수신하므로 Upstash Redis 내에서 효율적인 실시간 커뮤니케이션이 가능합니다.

Next.js 앱 라우터에서 서버 전송 이벤트 API 생성

서버 전송 이벤트는 여러 클라이언트 요청 없이 실시간으로 새 데이터를 보내는 강력한 방법입니다. 기존의 요청-응답 메커니즘과 달리 SSE는 수명이 긴 단일 HTTP 연결을 통해 서버에서 클라이언트로의 단방향 데이터 흐름을 가능하게 합니다.

Next.js 앱 라우터에서 서버 전송 이벤트를 구현하는 방법은 다음과 같습니다 👇🏻

// File: app/api/stream/route.js
 
// Prevents this route's response from being cached on Vercel
export const dynamic = 'force-dynamic'
 
export async function GET() {
 const encoder = new TextEncoder()
 // Create a streaming response
 const customReadable = new ReadableStream({
 start(controller) {
 const message = 'Hey, I am a message.'
 controller.enqueue(encoder.encode(`data: ${message}\n\n`))
 },
 })
 // Return the stream response and keep the connection alive
 return new Response(customReadable, {
 // Set the headers for Server-Sent Events (SSE)
 headers: {
 'Content-Type': 'text/event-stream; charset=utf-8',
 Connection: 'keep-alive',
 'Cache-Control': 'no-cache, no-transform',
 'Content-Encoding': 'none'
 },
 })
}

Next.js 서버 작업을 사용하여 Upstash Redis에 메시지 게시

Next.js 서버 작업을 사용하면 Next.js의 프런트엔드 코드 내에서 직접 서버 측 논리를 정의할 수 있습니다. 이렇게 하면 API 경로를 수동으로 생성하는 프로세스와 양식 제출 상태를 제출하고 추적하는 번거로움이 줄어듭니다.

use server 사용 함수 상단에서 함수가 서버 측에서만 실행되는지 확인할 수 있습니다. 양식 제출 서버 작업 내에서 message를 추출합니다. 양식에서 값을 얻으려면 Vercel Header를 사용하여 사용자의 국가를 얻고 해당 정보를 posts에 메시지로 게시하세요. Upstash Redis 메시지 채널.

// File: app/actions.jsx
 
'use server'
 
import { Redis } from '@upstash/redis'
import { headers } from 'next/headers'
 
// The function that takes care of obtaining the country code from Vercel headers
// And publishing messages to the Upstash Redis database with the current timestamp
export async function publishNotification(formData) {
 'use server'
 const redis = Redis.fromEnv()
 
 // Extract the message in the form submitted
 const message = formData.get('message')
 
 // Obtain country of the user using Vercel's x-vercel-ip-country header
 const headersList = headers()
 const country = headersList.get('x-vercel-ip-country')
 
 // Publish the message to the "posts" channel in Upstash Redis
 await redis.publish(
 'posts',
 JSON.stringify({
 message,
 country,
 date: new Date().toString(),
 }))
}

양식이 제출될 때 이 서버 작업을 호출하려면 이를 action 양식에 대한 핸들러로 전달합니다. 이벤트.

// File: app/page.jsx
 
// Import the server action
import { publishNotification } from './actions'
 
const Home = () => {
 return (
 <>
 <div>
 <form
 
 /* set the server action to invoked as form is submitted */
 action={publishNotification}
 
 >
 {/* Place a client side form component here */}
 </form>
 </div>
 </>
 )
}
 
export default Home

React의 useFormStatus 후크를 사용하여 양식 제출 중에 보류 상태를 표시하도록 Next.js 프런트엔드 설정

다음 코드는 양식 제출을 처리하고 pending를 표시하기 위한 Next.js 양식 클라이언트 측 구성 요소의 설정을 보여줍니다. React의 useFormStatus를 사용하여 상태 후크. 코드의 핵심 요소를 분석해 보겠습니다.

  • 최근 출시된 [useFormStatus 가져오기 React의 후크](https://react.dev/reference/react-dom/hooks/useFormStatus)는 마지막 양식 제출의 상태 정보를 제공합니다.
  • pending 사용 양식 제출이 진행 중인지 여부를 나타내는 상태 반응 변수입니다.
  • 제출이 보류 중이 아닌 경우 reset 양식입니다.
  • pending 사용 양식의 조건부 상태를 표시하는 부울입니다.
'use client'
 
import { useEffect } from 'react'
import { useFormStatus } from 'react-dom'
 
const Form = () => {
 
 // Use React's useFormStatus hook to detect form submission state
 const { pending } = useFormStatus()
 
 useEffect(() => {
 // If the form is not pending, reset the form
 if (!pending) document.getElementById('publish-form').reset()
 }, [pending])
 
 return (
 <>
 <input placeholder="Your message" className="border rounded px-3 outline-none focus:border-black/50 py-2" type="text" name="message" required />
 <button
 /* Disable button click while the form submission is pending */
 disabled={pending}
 className="hover:border-black/50 max-w-max border rounded py-1 px-3" type="submit"
 >
 {/* Display "pending" state placeholder */}
 {pending ? (
 <div className="flex flex-row gap-x-2 items-center">
 <div className="animate-spin border border-gray-800 rounded-full h-[15px] w-[15px]"></div>
 <span>Publishing</span>
 </div>
 ) : (
 <>Publish Notification &rarr;</>
 )}
 </button>
 </>
 )
}
 
export default Form

서버에서 보낸 이벤트를 지속적으로 수신하도록 Next.js 프런트엔드 설정

이 섹션에서는 서버에서 보낸 이벤트 API 메시지에 대한 최소 리스너를 설정하는 방법과 SSE API에 대한 연결을 유지하는 접근 방식을 알아봅니다.

React 프론트엔드에서 서버 전송 이벤트 API 수신

React의 클라이언트 측 구성 요소에서 SSE API를 수신하기 위해 useEffect를 사용합니다. 후크. SSE API에 대한 연결을 설정하려면 새 EventSource를 생성하세요. /api/stream을 가리키는 인스턴스 끝점. 그런 다음 message에 대한 이벤트 리스너를 연결합니다. 스트림에서 들어오는 데이터가 JSON으로 구문 분석되고 추가 처리되거나 구성 요소에 표시되는 이벤트입니다.

마지막으로, 코드에는 구성 요소가 마운트 해제될 때 SSE 연결을 닫아 잠재적인 메모리 누수를 방지하는 정리 기능이 포함되어 있습니다.

import { useEffect, useState } from 'react'
 
const ClientSideComponent = () => {
 
 useEffect(() => {
 
 // Initiate the first call to connect to SSE API
 const eventSource = new EventSource('/api/stream')
 
 eventSource.addEventListener('message', (event) => {
 // Parse the data received from the stream into JSON
 // Add it the list of messages seen on the page
 const tmp = JSON.parse(event.data)
 // Do something with the obtained message
 })
 
 // As the component unmounts, close listener to SSE API
 return () => {
 eventSource.close()
 }
 
 }, [])
 
 return <></>
}
 
export default ClientSideComponent

React 프론트엔드에서 서버 전송 이벤트 API에 대한 연결 유지

React 구성 요소의 향상된 버전에서는 오류를 처리하고 자동으로 다시 연결하여 SSE API에 대한 지속적이고 지속적인 연결을 보장하는 메커니즘을 구현했습니다.

이는 connectToStream을 통해 달성됩니다. SSE API에 대한 연결 설정 및 유지를 담당하는 기능입니다.

기능에 대한 분석은 다음과 같습니다 👇🏻

  1. 초기 연결 및 메시지 처리:

이 함수는 새로운 EventSource를 생성합니다. 예를 들어 /api/stream에 연결 중입니다. 끝점.

// Function to take care of initial connect to the SSE API
// Also, it reconnects to the SSE API as soon as it shuts down
// This keeps the connection alive - forever with micro second delays
const connectToStream = () => {
 // Connect to /api/stream as the SSE API source
 const eventSource = new EventSource('/api/stream')
 // ..
}

또한 message에 대한 이벤트 리스너를 설정합니다. 스트림에서 들어오는 데이터가 JSON으로 구문 분석되는 이벤트입니다. 그런 다음 구문 분석된 데이터를 React 구성 요소에서 처리하거나 표시할 수 있습니다.

const connectToStream = () => {
 // ...
 eventSource.addEventListener('message', (event) => {
 // Parse the data received from the stream into JSON
 // Add it the list of messages seen on the page
 const tmp = JSON.parse(event.data)
 setPosts((prevPosts) => [...prevPosts, tmp])
 })
 // ...
}
  1. 오류 처리 및 자동 재연결:

error에 대한 추가 이벤트 리스너가 설정되었습니다. 이벤트. 연결 실패 등의 오류가 발생하면 이벤트 소스가 닫힙니다.

닫은 후 함수는 setTimeout를 활용합니다. 1밀리초의 최소 지연 후에 다시 연결을 트리거합니다. 이러한 작은 지연은 빠른 연결 시도로 인해 서버에 부담을 주지 않으면서 보다 원활하고 지속적인 재연결 프로세스를 만드는 데 도움이 됩니다.

// In case of any error, close the event source
// So that it attempts to connect again
eventSource.addEventListener('error', () => {
 eventSource.close()
 setTimeout(connectToStream, 1)
})
  1. SSE API 소스 폐쇄 처리:

onclose 이벤트는 SSE API 소스가 닫히는 시기를 감지하는 데 활용됩니다. 종료 시 함수는 잠시 지연된 후 스트림에 연결하려는 또 다른 시도를 예약합니다.

// As soon as SSE API source is closed, attempt to reconnect
eventSource.onclose = () => {
 setTimeout(connectToStream, 1)
}

이러한 전략을 결합함으로써 이 기능은 SSE API에 대한 연결이 지속적으로 유지되도록 보장합니다. 오류나 종료가 발생하더라도 React 구성 요소는 최소한의 지연으로 계속 재연결을 시도하여 효과적으로 지속적인 연결을 유지합니다.

Vercel에 배포

저장소를 Vercel에 배포할 준비가 되었습니다. Vercel을 사용하여 원활하게 배포하려면 아래 단계를 따르세요 👇🏻

  • GitHub Repository 만들기 앱 코드로
  • New Project 만들기 Vercel 대시보드에서
  • 생성된 GitHub Repository 연결 새 프로젝트로
  • 아래로 스크롤하여 Environment Variables을 업데이트합니다. .env에서 로컬에서
  • 배치하세요! 🚀

참고자료