برنامه نویسی

چت بدون سرور در AWS با رویدادهای AppSync

در مقاله قبلی خود نشان داده‌ام که ایجاد یک برنامه چت بلادرنگ با استفاده از AWS IoT Core چقدر آسان است. همانطور که در آنجا ذکر کردم، می‌خواهم پیاده‌سازی همان راه‌حل را با استفاده از AppSync Event API اخیراً اعلام‌شده کشف کنم. در این مقاله، من این کار را انجام خواهم داد. در طول مسیر، شباهت ها و تفاوت های بین این دو رویکرد را مورد بحث قرار می دهیم، در حالی که اصول اولیه رویدادهای AppSync، انتخاب های معماری، هشدارها و موارد دیگر را پوشش می دهیم. مانند دفعه قبل، من یک پروژه CDK را اضافه می کنم تا بتوانید با استفاده از یک کلاینت ساده آن را به صورت زنده با آن بازی کنید.

رویدادهای AppSync

رویدادهای AppSync در اکتبر 2024 اعلام شد و واقعاً هیجان انگیز به نظر می رسد. من با تکرار آنچه قبلاً در مورد خود سرویس گفته شده است، شما را خیلی اذیت نمی کنم، بنابراین به طور خلاصه، با استناد به راهنمای AWS:

رویدادهای AWS AppSync به شما امکان می‌دهد APIهای WebSocket بدون سرور ایمن و کارآمد ایجاد کنید که می‌تواند داده‌های رویداد را در زمان واقعی برای میلیون‌ها مشترک پخش کند، بدون اینکه نیازی به مدیریت اتصالات یا مقیاس‌گذاری منابع داشته باشید.

من فوراً خواستم آن را امتحان کنم، اما به سرعت متوجه شدم که هنوز “جوان” است و فاقد بسیاری از ویژگی هایی است که برای موارد استفاده زیادی لازم است. به عنوان مثال، در حال حاضر هیچ راه مستقیمی برای ذخیره پیام های کانال ها در هر نقطه وجود ندارد. انتظار داشتم که حداقل بتوانید یک تابع Lambda را راه اندازی کنید و کاری سفارشی با پیام ها انجام دهید، مانند ذخیره آنها در DynamoDB. پردازش پیام از طریق کنترل کننده های فضای نام با استفاده از امکان پذیر است onPublish و onSubscribe با این حال، از آنجایی که آنها بر روی زمان اجرا جاوا اسکریپت AppSync اجرا می شوند، هیچ امکانی برای انجام کارهای بیشتر از پردازش یا فیلتر کردن محموله وجود ندارد.

در این مقاله، من عمدتاً بر روی کار بر روی کمبود قابلیت‌های پایداری تمرکز خواهم کرد. یک جلسه عالی re:Invent 2024 شامل ارائه مفصلی از این سرویس، پرداختن به معایب و پیشنهاد راه حل های جایگزین است. این جلسه بسیار آموزنده است و همچنین به نقشه راه می پردازد که طبق آن تمام ویژگی های گمشده (و بیشتر) برای ارائه برنامه ریزی شده است. اکنون، می‌خواهم با رویدادهای AppSync، احتمالات تداوم رویداد را بررسی کنم.

موضوع تداوم رویدادها

در جلسه re:Invent که در بالا به اشتراک گذاشته شد، ارائه‌دهنده موضوع تداوم رویداد را در حدود ساعت 44:35 بیان می‌کند و راه‌حل‌ها را به‌عنوان «الگوهای پیشرفته» ارائه می‌کند. راه حل اساساً داشتن یک API در کنار AppSync Event API است که برای تداوم رویدادها به طور جداگانه استفاده می شود. این می تواند چیزی شبیه به:

معماری پیشنهادی

از آنجایی که API جانبی به هر حال برای واکشی پیام‌های قبلی وجود دارد، افزودن یک نقطه پایانی دیگر برای ذخیره پیام‌ها کار بزرگی نیست. نسبتاً ساده است، کار خواهد کرد، اما یک مشکل وجود دارد. به این ترتیب مشتری در هنگام انتشار پیام‌ها با دو درخواست مواجه می‌شود – یکی برای AppSync Event API برای انتشار آن برای مشترکین، و دیگری برای API جانبی که در واقع رویداد را در پایگاه داده ادامه می‌دهد. اگر مشکلی در مورد تداوم رویدادها توسط API وجود داشته باشد، بین آنچه که ادامه دارد و آنچه مشترکین دریافت می کنند ناسازگاری وجود خواهد داشت. از آنجایی که مشتری باید رویدادها را به دو مقصد بفرستد و هر دو باید موفق شوند، مدیریت مجدد در صورت شکست نیز به پیچیدگی می‌افزاید. من ترجیح می دهم این را یک ضد الگو بنامم.

نگاهی به یک راه حل جایگزین

من می خواهم یک رویکرد جایگزین برای این چالش ارائه دهم. علاوه بر نقطه پایانی WebSockets، AppSync Event API دارای یک نقطه پایانی HTTP است که به عنوان یک ویژگی منظم برای ادغام نه تنها مشتریان frontend، بلکه همچنین backendهایی که می توانند رویدادها را در آن منتشر کنند، برجسته شده است. برای دستیابی به یکپارچگی و راه حل قوی تر، استفاده از DynamoDB Streams و EventBridge Pipes می تواند راه حلی باشد. به این ترتیب مشتری هنگام ارسال پیام فقط یک درخواست می کند و مشترکین همیشه پیام هایی را دریافت می کنند که واقعاً ادامه دارند. در واقع، این بدان معناست که مشتری اصلاً از نقطه پایانی HTTP رویدادهای AppSync استفاده نمی‌کند، بلکه برای ارسال پیام‌ها به API جانبی متکی است و فقط از طریق نقطه پایانی بلادرنگ به پیام‌های دریافتی گوش می‌دهد. نمودار زیر این معماری را با وضوح بیشتری نشان می دهد.

معماری جایگزین

این امر با استفاده از برخی از قابلیت های EventBridge امکان پذیر است. یعنی جریان‌های DynamoDB روی جدول پیام‌ها فعال می‌شوند و هر پیام جدید را از طریق یک EventBridge Pipe به مقصد API متصل می‌کنند که به نقطه پایانی واقعی HTTP رویدادهای AppSync متصل است.

از آنجایی که من از طرفداران پر و پا قرص CDK هستم، و دوست دارم که در حد فاصل باشم، به چند ماژول آلفا از CDK تکیه می کنم: @aws-cdk/aws-pipes-alpha، @aws-cdk/aws-pipes-sources-alpha، @aws-cdk/aws-pipes-targets-alpha و این چیزی است که برای اتصال با DynamoDB Streams لازم است:

// EventBridge Pipe DynamoDB Stream Source
const dynamoDbStreamSource = new DynamoDBSource(table, {
    startingPosition: DynamoDBStartingPosition.LATEST,
});

// EventBridge API Destination
const appSyncEventsApiDestination = new ApiDestination(this, 'AppSyncEventsApiDestination', {
    connection: appSyncEventsApiConnection,
    endpoint: appSyncEventsApiEndpoint,
    httpMethod: HttpMethod.POST,
});

// EventBridge Pipe with API Destination Target & Input Transformation
const pipe = new Pipe(this, 'EBPipe', {
    source: dynamoDbStreamSource,
    target: new ApiDestinationTarget(appSyncEventsApiDestination, {
        inputTransformation: InputTransformation.fromObject({
            channel: 'serverlesschat/channels/' + '<$.dynamodb.NewImage.channel.S>',
            events: [
                JSON.stringify({
                    channel: '<$.dynamodb.NewImage.channel.S>',
                    timestamp: '<$.dynamodb.NewImage.timestamp.S>',
                    username: '<$.dynamodb.NewImage.username.S>',
                    message: '<$.dynamodb.NewImage.message.S>',
                })
            ],
        }),
        // api key must be sent with each message
        headerParameters: {
            'X-Api-Key': appSyncEventsApiKey,
        }
    }),
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تبدیل ورودی برای تطبیق جریان‌های DynamoDB در قالب مورد نیاز نقطه پایانی AppSync Events انجام می‌شود:

{
  "channel": "string",
  "events": ["..."]
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

توجه: events آرایه‌ای از رشته‌ها است، از این رو پیام‌های json در طول تبدیل رشته‌بندی می‌شوند.

برای یک نکته: فعال کردن گزارش‌های CloudWatch برای Pipe with داده های اجرای لاگ روشن می تواند در زمان عیب یابی شما صرفه جویی کند.

مبادلات

مانند هر تصمیم دیگری در مورد معماری، معاوضه‌هایی وجود دارد، بنابراین اجازه دهید با اضافه کردن DynamoDB Streams و EventBridge Pipe به آنها بپردازیم. برای بهبود ثبات و ساده سازی ارتباط مشتری، سرعت تحویل پیام کاهش می یابد. این به چه معناست؟ تأخیر اندکی در تحویل پیام به مشتریان مشترک مشاهده می شود. این تعجب آور نیست زیرا پیام می رود
از طریق دروازه API و یک تابع Lambda، به یک جدول DynamoDB و از آنجا به AppSync Event API از طریق یک EventBridge Pipe، که اساساً یک تماس HTTP دیگر است، جریان می یابد. بنابراین، چیزهای زیادی در چند ده خط کد اتفاق می افتد. من فقط نمی توانم توجه کنم که راه حل IoT Core به طور کلی کمی سریع تر است. البته این مشکل زمانی حل خواهد شد که AppSync Events ارتباط دو طرفه WebSocket را دریافت کند.

مجوز

چند کلمه در مورد مجوز. ساده ترین راه برای شروع با AppSync Events استفاده از API Key auth است، و این دقیقاً چگونه این پروژه پیکربندی شده است. حالت های دیگر نیز پشتیبانی می شوند، بسیار استاندارد برای AWS: Cognito User Pool، IAM، OIDC، و AWS Lambda سفارشی. این انتخاب‌ها انعطاف‌پذیری زیادی را برای نیازهای مختلف مجوز ارائه می‌دهند، به ویژه با توجه به این واقعیت که می‌توان آن را در هر فضای نام پیکربندی کرد.

مجوز با EventBridge API Destination

همانطور که در کد CDK بالا مشاهده می شود، یک مقصد API با یک اتصال پیکربندی شده است تا هنگام ارسال پیام به نقطه پایانی AppSync Event HTTP API از مجوز پشتیبانی کند. علاوه بر این، هدف مقصد پیکربندی شده در EventBridge Pipe باید داشته باشد X-Api-Key هدر با هر درخواست برای دریافت پیام ارسال می شود. چیزی که من متوجه شدم این است که هنگامی که این هدر گم شده باشد، یا مقدار آن نادرست است – Connection تبدیل می شود Deauthorized به طور خودکار و در نتیجه کل لوله از کار می افتد. من راهی برای رفع آن پیدا نکردم، اما فقط برای نابود کردن و استقرار دوباره پشته. من مطمئن نیستم که برای تأیید مجدد مقصد API چه چیزی لازم است، اما از نقطه نظر تجربه توسعه‌دهنده بسیار ناخوشایند بود.

نسخه ی نمایشی و کد

مشابه مقاله گذشته، من یک کلاینت ساده HTML ایجاد کردم که توسط جاوا اسکریپت طراحی شده است تا این راه حل را آزمایش و نمایش دهد. به طور کلی، نمونه‌هایی در مورد پیکربندی کلاینت از Amplify استفاده می‌کنند که هنگام ساخت با چارچوب‌های SPA، کتابخانه‌ای مرتب است. من یک صفحه HTML ساده را انتخاب کردم که از مرورگر بومی استفاده می کند fetch و websocket API ها، بدون هیچ گونه وابستگی خارجی. اگر می‌خواهید خودتان مثال را اجرا کنید، لازم نیست نگران نکات فنی باشید، اما اگر می‌خواهید در مورد نحوه اتصال به رویدادهای AppSync بدون Amplify بیشتر غوطه ور شوید، در صورت تمایل با درک پروتکل Event API WebSocket AWS مشورت کنید. راهنما و کد من

https://github.com/imflamboyant/serverless-aws-chat

دستورالعمل‌های استقرار و استفاده AWS در فایل README مخزن ارائه شده است.

نتیجه گیری

در این مقاله، تجربه خود را در ساختن یک راه‌حل چت بی‌درنگ آشنا، این بار با یک پیشنهاد جدید AWS – AppSync Events به اشتراک گذاشته‌ام. این شبیه به IoT Core است، بیشتر به دلیل نحوه سازماندهی اشتراک‌ها با فضاهای نام/کانال‌ها، اما باید اعتراف کنم که تجربه توسعه‌دهنده «بومی‌تری» را به شما می‌دهد.

نقشه راه به اشتراک گذاشته شده در re:Invent 2024 امیدوارکننده به نظر می رسد و بیان می کند که می توانیم انتظار ویژگی هایی مانند ارتباط دو طرفه وب سوکت، گزینه های پایداری داده و کنترل کننده های لامبدا را داشته باشیم. وقتی همه اینها منتشر شد، من واقعاً معتقدم که این یکی از مهم ترین خدمات AWS برای ساخت برنامه های مدرن خواهد بود.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا