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

QStash를 사용하여 Redis 상태를 데이터베이스와 원활하게 동기화

이전 기사에서는 Redis를 사용하여 전체 스택 Next.js 앱에 사용자 할당량 상태를 저장하는 방법에 대해 논의했습니다. Redis는 일반적으로 데이터베이스보다 훨씬 빠르기 때문에 이렇게 하면 애플리케이션의 성능을 향상시킬 수 있습니다.

Upstash Redis는 특히 완전 관리형 Redis 데이터베이스이고 HTTP를 통해 액세스할 수 있으므로 이 사용 사례에 탁월한 선택입니다. 즉, Vercel과 같은 에지 런타임을 사용하여 대기 시간을 최소화하면서 사용자 가까이에서 코드를 실행할 수도 있습니다.

QStash란 무엇인가요?

QStash는 서버리스 및 에지 런타임을 위한 HTTP 기반 메시징 및 예약 솔루션입니다. . 즉, HTTP 요청을 전송하여 CRON 작업을 실행할 수 있습니다. .

CRON 작업은 특정 시간에 실행되도록 작업을 예약하는 좋은 방법입니다. 이 CRON 작업은 애플리케이션이나 최종 사용자의 성능에 영향을 주지 않고 실행하려는 만큼의 시간이 걸릴 수 있습니다.

이 문서에서 CRON 작업의 목표는 Redis의 사용자 할당량 상태를 데이터베이스와 동기화하는 것입니다. 이 작업을 매시간 실행하도록 하겠습니다. .

QStash를 사용하여 CRON 작업 엔드포인트 생성

다음은 Redis에서 사용자 할당량 상태를 처리하는 방법에 대한 이전 기사를 간단히 요약한 것입니다.

// Key stored in Redis. A key is created for each user, and made unique by their ID.
const quotaKey = `user:${userId}:quota`;
 
// Call the INCR command to increment the value of the key by 1.
const quota = await redis.incr(quotaKey);
 
// If the value of the key is 1, it means the key has been created.
// We can set an expiration date of 24 hours to this key by using the EXPIRE command.
if (quota === 1) {
 await redis.expire(quotaKey, 60 * 60 * 24);
}

이 코드가 주어지면 이제 QStash를 사용하여 CRON 작업 끝점을 만들 수 있습니다. CRON 작업 엔드포인트는 URL /api/cron/update-usage에서 트리거됩니다. .

Next.js 엔드포인트를 위한 새 파일을 만들어 보겠습니다.

touch pages/api/cron/update-usage.ts

그런 다음 QStash만이 이 끝점을 트리거할 수 있는지 확인하고 싶습니다. 이것이 @upstash/qstash입니다. 우리를 위해 처리합니다. 이렇게 하지 않으면 누구나 잠재적으로 보안 문제를 일으킬 수 있는 CRON 작업 엔드포인트를 트리거합니다.

@upstash/qstash을 설치하자 :

npm install @upstash/qstash

이제 CRON 작업 엔드포인트의 코드에 집중할 수 있습니다.

다음은 우리가 할 일을 간단히 요약한 것입니다:

  • SCAN을 사용하여 Redis에서 모든 사용자의 할당량 키를 가져옵니다. (커서 기반 페이지 매김 수행) .
  • SCAN에서 찾은 각 키에 대해 , users을 생성하세요 사용자 ID와 할당량을 포함하는 객체 배열
  • users 내부의 각 사용자에 대한 거래를 생성합니다. 데이터베이스의 할당량을 업데이트하기 위한 배열입니다. 이는 Prisma를 사용하여 수행됩니다.
  • verifySignature를 사용하여 엔드포인트 함수 내보내기 @upstash/qstash/nextjs의 함수 QStash만이 엔드포인트를 트리거할 수 있도록 합니다.

전체 코드 엔드포인트는 여기에 있습니다. 코드의 모든 측면에 대해 주석을 달았습니다.

// /pages/api/cron/update-usage.ts
import type { NextApiRequest, NextApiResponse } from "next";
 
import { verifySignature } from "@upstash/qstash/nextjs";
 
import prisma from "@/lib/prisma";
 
// Generate an Upstash Redis instance using environment variables.
// Make sure those are defined in your .env file.
const redis = new Redis({
 url: process.env.UPSTASH_REDIS_REST_URL!,
 token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});
 
// Required by `@upstash/qstash`.
export const config = { api: { bodyParser: false } };
 
// Update the usage of every user by pulling the data from the Redis database into the Prisma database.
async function handler(req: NextApiRequest, res: NextApiResponse) {
 // Contains all the keys found during the `SCAN`.
 const keys: string[] = [];
 // Current position of the cursor, updated after each `SCAN`.
 let cursor = 0;
 
 // Execute the cursor-based pagination using the `SCAN` command.
 // Redis return `0` when the cursor is at the end of the pagination.
 do {
 const [nextCursor, newKeys] = await redis.scan(cursor, {
 // Match the pattern of the keys we want to find, where `*` is a wildcard.
 match: "user:*:quota",
 // Limit the number of keys returned by the `SCAN` command.
 count: 10,
 });
 
 cursor = nextCursor;
 keys.push(...newKeys);
 } while (cursor !== 0);
 
 // Array of objects containing the user's ID and their quota.
 const users: { id: number; quota: number }[] = [];
 
 // Get the usage of each user from Redis based on the keys found.
 for (const key of keys) {
 // A key should be in the format `user:${id}:quota`. Split the key to get the ID.
 const id = key.split(":")[1];
 // Get the current quota of the user using the `GET` command.
 const quota = await redis.get(`user:${id}:quota`);
 
 users.push({ id: parseInt(id, 10), quota });
 }
 
 // Create a transaction for each user to update their quota in the database.
 const promises = users.map((user) =>
 prisma.user.update({
 where: { id: user.id },
 data: { quota: user.quota },
 }),
 );
 
 // Run all transactions.
 await Promise.all(promises);
 
 return res.status(200).json({ message: "OK" });
}
 
// Export the handler with the `verifySignature` function to make sure only
// QStash can authenticate to trigger the CRON job.
export default verifySignature(handler);

가장 어려운 부분이 끝났습니다!

QStash 설정

이제 코드를 푸시하기 전에 QStash를 설정해야 합니다. QStash는 넉넉한 무료 등급을 제공하므로 매일 최대 500개의 요청을 사용할 수 있습니다. .

Upstash 콘솔에 로그인하고 QStash를 클릭하세요. 탭.

그런 다음 요청 빌더를 사용하여 새로운 예약된 CRON 작업을 생성해 보겠습니다. . 직관적인 UI 덕분에 매우 간단합니다:

QStash를 사용하여 Redis 상태를 데이터베이스와 원활하게 동기화

일정을 클릭한 후 버튼을 누르고 아래로 스크롤하면 예약된 작업에 CRON 작업이 표시됩니다. 섹션:

QStash를 사용하여 Redis 상태를 데이터베이스와 원활하게 동기화

마지막 단계에서는 2개의 환경 변수를 설정해야 합니다. Next.js 애플리케이션에서. 해당 변수는 Next.js 애플리케이션이 호스팅되는 위치(이 경우 Vercel)에 추가됩니다.

요청 작성기에서 섹션에는 복사할 준비가 된 2개의 환경 변수가 있습니다:

  • QSTASH_CURRENT_SIGNING_KEY
  • QSTASH_NEXT_SIGNING_KEY

이는 들어오는 메시지를 인증하는 데 필요합니다. 그렇지 않으면 누구나 귀하의 엔드포인트에 전화할 수 있습니다.

QStash를 사용하여 Redis 상태를 데이터베이스와 원활하게 동기화

해당 변수가 있으면 Vercel 프로젝트에 추가할 수 있습니다.

이렇게 하려면 Vercel 프로젝트로 이동하여 설정을 클릭하세요. 그런 다음 환경 변수에서 :

QStash를 사용하여 Redis 상태를 데이터베이스와 원활하게 동기화

2개의 환경 변수를 추가한 후 이제 코드를 푸시할 수 있습니다.

QStash는 주기적으로 CRON 작업 엔드포인트를 트리거하고 매시간 모든 사용자의 사용량을 업데이트합니다.

결론

Upstash는 서버리스 환경을 위한 다양한 도구를 제공합니다. QStash와 Redis를 함께 사용하여 다양한 사용 사례에 맞는 성능이 뛰어나고 확장 가능한 애플리케이션을 만들 수 있습니다.

실시간으로 보고 싶다면 스프레드시트를 API로 전환하는 도구인 fastsheet에 동일한 시스템이 구현되어 있습니다.