From f347aa318c34828c04f140d1fadd39d5ffd82c81 Mon Sep 17 00:00:00 2001 From: Dev Singh Date: Tue, 4 Nov 2025 23:09:12 -0600 Subject: [PATCH 1/6] Update ScanTickets.page.tsx --- src/ui/pages/tickets/ScanTickets.page.tsx | 167 ++++++++++++++++++---- 1 file changed, 141 insertions(+), 26 deletions(-) diff --git a/src/ui/pages/tickets/ScanTickets.page.tsx b/src/ui/pages/tickets/ScanTickets.page.tsx index bbbd5c26..78b14a8c 100644 --- a/src/ui/pages/tickets/ScanTickets.page.tsx +++ b/src/ui/pages/tickets/ScanTickets.page.tsx @@ -125,6 +125,8 @@ const ScanTicketsPageInternal: React.FC = ({ const [availableTickets, setAvailableTickets] = useState( [], ); + const [unclaimableTicketsForSelection, setUnclaimableTicketsForSelection] = + useState([]); const [ticketItems, setTicketItems] = useState; @@ -552,39 +554,74 @@ const ScanTicketsPageInternal: React.FC = ({ // Fetch purchases for this email const response = await getPurchasesByEmail(email); - // Combine all valid tickets (both merch and tickets) and filter by selected item - const allValidTickets = [ + // --- REFACTORED LOGIC --- + + // 1. Get ALL purchases for the selected item, regardless of status. + const allPurchasesForItem = [ ...response.tickets.filter( - (t) => - t.valid && - !t.refunded && - t.purchaserData.productId === selectedItemFilter, + (t) => t.purchaserData.productId === selectedItemFilter, ), ...response.merch.filter( - (m) => - m.valid && - !m.refunded && - m.purchaserData.productId === selectedItemFilter, + (m) => m.purchaserData.productId === selectedItemFilter, ), ]; - if (allValidTickets.length === 0) { + // 2. Check if we found anything at all. + if (allPurchasesForItem.length === 0) { setError( - "No valid tickets found for this user and selected event/item.", + "No purchases found for this user and selected event/item.", ); setShowModal(true); setIsLoading(false); return; } - if (allValidTickets.length === 1) { - // Only one valid ticket, mark it automatically - await markTicket(allValidTickets[0]); + // 3. Partition these purchases. + // A "claimable" ticket is valid, not refunded, and not already fulfilled. + const claimableTickets = allPurchasesForItem.filter( + (p) => p.valid && !p.refunded && !p.fulfilled, + ); + + // An "unclaimable" ticket is everything else. + const unclaimableTickets = allPurchasesForItem.filter( + (p) => !p.valid || p.refunded || p.fulfilled, + ); + + // 4. Apply new logic based on the user's request. + + // Case 1: No claimable tickets. + if (claimableTickets.length === 0) { + let errorMessage = "No valid, unclaimed tickets found for this user."; + if (unclaimableTickets.length > 0) { + // Provide a more specific error based on the first unclaimable ticket. + const firstReason = unclaimableTickets[0]; + if (firstReason.fulfilled) { + errorMessage = + "All tickets for this event have already been claimed."; + } else if (firstReason.refunded) { + errorMessage = "This user's ticket has been refunded."; + } else if (!firstReason.valid) { + errorMessage = "This user's ticket is invalid."; + } + } + setError(errorMessage); + setShowModal(true); + setIsLoading(false); + return; + } + + // Case 2: Exactly one claimable ticket AND no other context (unclaimable tickets) to show. + // We can auto-mark this one. + if (claimableTickets.length === 1 && unclaimableTickets.length === 0) { + await markTicket(claimableTickets[0]); } else { - // Multiple valid tickets, show selection modal - setAvailableTickets(allValidTickets); + // Case 3: Multiple claimable tickets OR a mix of claimable/unclaimable tickets. + // Show the selection modal to provide full context. + setAvailableTickets(claimableTickets); + setUnclaimableTicketsForSelection(unclaimableTickets); setShowTicketSelection(true); } + // --- END REFACTORED LOGIC --- setIsLoading(false); } catch (err: any) { @@ -607,16 +644,19 @@ const ScanTicketsPageInternal: React.FC = ({ const markTicket = async (ticket: APIResponseSchema) => { try { setIsLoading(true); - const qrData = - ticket.type === ProductType.Ticket - ? { type: "ticket", ticketId: ticket.ticketId } - : { + + // Ensure the checkInTicket API can handle the data structure + // This assumes ticket.ticketId holds the unique identifier (stripe_pi for merch, ticket_id for ticket) + const checkInData = + ticket.type === ProductType.Merch + ? { type: "merch", stripePi: ticket.ticketId, email: ticket.purchaserData.email, - }; + } + : { type: "ticket", ticketId: ticket.ticketId }; - const result = await checkInTicket(qrData); + const result = await checkInTicket(checkInData); if (!result.valid) { throw new Error("Ticket is invalid."); @@ -625,10 +665,14 @@ const ScanTicketsPageInternal: React.FC = ({ setScanResult(result); setShowModal(true); setShowTicketSelection(false); + setAvailableTickets([]); + setUnclaimableTicketsForSelection([]); setIsLoading(false); } catch (err: any) { setIsLoading(false); setShowTicketSelection(false); + setAvailableTickets([]); + setUnclaimableTicketsForSelection([]); if (err.response && err.response.data) { setError( err.response.data @@ -797,14 +841,18 @@ const ScanTicketsPageInternal: React.FC = ({ Ticket Details: Type: {scanResult?.type.toLocaleUpperCase()} {scanResult.purchaserData.productId && ( - Product: {scanResult.purchaserData.productId} + + Product: {scanResult.purchaserData.productId} + )} Token ID: {scanResult?.ticketId} Email: {scanResult?.purchaserData.email} {scanResult.purchaserData.quantity && ( - Quantity: {scanResult.purchaserData.quantity} + + Quantity: {scanResult.purchaserData.quantity} + )} {scanResult.purchaserData.size && ( Size: {scanResult.purchaserData.size} @@ -824,6 +872,8 @@ const ScanTicketsPageInternal: React.FC = ({ opened={showTicketSelection} onClose={() => { setShowTicketSelection(false); + setAvailableTickets([]); + setUnclaimableTicketsForSelection([]); setManualInput(""); }} title="Select a Ticket" @@ -832,7 +882,7 @@ const ScanTicketsPageInternal: React.FC = ({ > - Multiple valid tickets found. Please select which one to mark: + Multiple purchases found. Please select an available one to mark: {availableTickets.map((ticket, index) => ( = ({ withBorder style={{ cursor: "pointer" }} onClick={() => markTicket(ticket)} + sx={(theme) => ({ + borderLeft: `5px solid ${theme.colors.green[6]}`, + "&:hover": { + backgroundColor: theme.colors.gray[0], + }, + })} > @@ -856,17 +912,76 @@ const ScanTicketsPageInternal: React.FC = ({ {ticket.purchaserData.size && ( Size: {ticket.purchaserData.size} )} + + Status: AVAILABLE + Ticket ID: {ticket.ticketId} ))} + + {/* Render Unclaimable Tickets */} + {unclaimableTicketsForSelection.map((ticket, index) => { + let status = "Unknown"; + let color = "gray"; + if (ticket.fulfilled) { + status = "ALREADY CLAIMED"; + color = "orange"; + } else if (ticket.refunded) { + status = "REFUNDED"; + color = "red"; + } else if (!ticket.valid) { + status = "INVALID"; + color = "red"; + } + + return ( + ({ + borderLeft: `5px solid ${theme.colors[color][6]}`, + })} + > + + + {ticket.type.toUpperCase()} -{" "} + {ticket.purchaserData.productId} + + + Email: {ticket.purchaserData.email} + + {ticket.purchaserData.quantity && ( + + Quantity: {ticket.purchaserData.quantity} + + )} + {ticket.purchaserData.size && ( + + Size: {ticket.purchaserData.size} + + )} + + Status: {status} + + + Ticket ID: {ticket.ticketId} + + + + ); + })} + + ) : ( + // Single Scan Result scanResult && ( = ({ )} + {/* Ticket Selection Modal (for multi-select) */} { setShowTicketSelection(false); setAvailableTickets([]); setUnclaimableTicketsForSelection([]); + setSelectedTicketsToClaim(new Set()); // Clear selection setManualInput(""); }} - title="Select a Ticket" + title="Select Ticket(s) to Claim" size="lg" centered + withCloseButton={!isLoading} + closeOnClickOutside={!isLoading} + closeOnEscape={!isLoading} > + - Multiple purchases found. Please select an available one to mark: + Multiple purchases found. Please select which one(s) to claim: + {/* Render Claimable Tickets with Checkboxes */} {availableTickets.map((ticket, index) => ( markTicket(ticket)} sx={(theme) => ({ borderLeft: `5px solid ${theme.colors.green[6]}`, - "&:hover": { - backgroundColor: theme.colors.gray[0], - }, })} > - - - {ticket.type.toUpperCase()} -{" "} - {ticket.purchaserData.productId} - - Email: {ticket.purchaserData.email} - {ticket.purchaserData.quantity && ( - - Quantity: {ticket.purchaserData.quantity} + + { + const newSet = new Set(selectedTicketsToClaim); + if (event.currentTarget.checked) { + newSet.add(ticket.ticketId); + } else { + newSet.delete(ticket.ticketId); + } + setSelectedTicketsToClaim(newSet); + }} + aria-label={`Select ticket ${ticket.ticketId}`} + /> + + + {ticket.type.toUpperCase()} -{" "} + {ticket.purchaserData.productId} + + Email: {ticket.purchaserData.email} + {ticket.purchaserData.quantity && ( + + Quantity: {ticket.purchaserData.quantity} + + )} + {ticket.purchaserData.size && ( + Size: {ticket.purchaserData.size} + )} + + Status: AVAILABLE - )} - {ticket.purchaserData.size && ( - Size: {ticket.purchaserData.size} - )} - - Status: AVAILABLE - - - Ticket ID: {ticket.ticketId} - - + + Ticket ID: {ticket.ticketId} + + + ))} {/* Render Unclaimable Tickets */} {unclaimableTicketsForSelection.map((ticket, index) => { let status = "Unknown"; - let color = "gray"; + let color: MantineColor = "gray"; if (ticket.fulfilled) { status = "ALREADY CLAIMED"; color = "orange"; @@ -978,15 +1096,24 @@ const ScanTicketsPageInternal: React.FC = ({ + From 78575d3023c091ab7bed9eb44b790a4d365ab21f Mon Sep 17 00:00:00 2001 From: Dev Singh Date: Tue, 4 Nov 2025 23:21:32 -0600 Subject: [PATCH 3/6] Refactor ScanTickets.page.tsx for Mantine v5 styles --- src/ui/pages/tickets/ScanTickets.page.tsx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ui/pages/tickets/ScanTickets.page.tsx b/src/ui/pages/tickets/ScanTickets.page.tsx index a050c882..a65d9a33 100644 --- a/src/ui/pages/tickets/ScanTickets.page.tsx +++ b/src/ui/pages/tickets/ScanTickets.page.tsx @@ -11,8 +11,9 @@ import { LoadingOverlay, Select, TextInput, - Checkbox, // Added - MantineColor, // Added + Checkbox, + MantineColor, + MantineTheme, // Added for v5 style prop } from "@mantine/core"; import { IconAlertCircle, IconCheck, IconCamera } from "@tabler/icons-react"; import jsQR from "jsqr"; @@ -997,7 +998,8 @@ const ScanTicketsPageInternal: React.FC = ({ key={`${ticket.ticketId}-${index}`} p="md" withBorder - sx={(theme) => ({ + // --- FIXED for v5 --- + style={(theme: MantineTheme) => ({ borderLeft: `5px solid ${theme.colors.green[6]}`, })} > @@ -1060,8 +1062,10 @@ const ScanTicketsPageInternal: React.FC = ({ key={`${ticket.ticketId}-${index}`} p="md" withBorder - style={{ cursor: "not-allowed", opacity: 0.6 }} - sx={(theme) => ({ + // --- FIXED for v5 --- + style={(theme: MantineTheme) => ({ + cursor: "not-allowed", + opacity: 0.6, borderLeft: `5px solid ${theme.colors[color][6]}`, })} > From cee28e0c018a180746fd1b5244568fede5508604 Mon Sep 17 00:00:00 2001 From: Dev Singh Date: Tue, 4 Nov 2025 23:42:08 -0600 Subject: [PATCH 4/6] Run prettier --- src/ui/pages/tickets/ScanTickets.page.tsx | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/ui/pages/tickets/ScanTickets.page.tsx b/src/ui/pages/tickets/ScanTickets.page.tsx index a65d9a33..3cba1ae7 100644 --- a/src/ui/pages/tickets/ScanTickets.page.tsx +++ b/src/ui/pages/tickets/ScanTickets.page.tsx @@ -581,9 +581,7 @@ const ScanTicketsPageInternal: React.FC = ({ // 2. Check if we found anything at all. if (allPurchasesForItem.length === 0) { - setError( - "No purchases found for this user and selected event/item.", - ); + setError("No purchases found for this user and selected event/item."); setShowModal(true); setIsLoading(false); return; @@ -755,9 +753,8 @@ const ScanTicketsPageInternal: React.FC = ({ ? firstFailure.reason.message : String(firstFailure.reason); } else if (firstFailure.status === "fulfilled") { - firstError = ( - firstFailure.value as { success: false; error: string } - ).error; + firstError = (firstFailure.value as { success: false; error: string }) + .error; } setError( `Failed to claim ${failedClaims.length} ticket(s). First error: ${firstError}`, @@ -943,18 +940,14 @@ const ScanTicketsPageInternal: React.FC = ({ Ticket Details: Type: {scanResult?.type.toLocaleUpperCase()} {scanResult.purchaserData.productId && ( - - Product: {scanResult.purchaserData.productId} - + Product: {scanResult.purchaserData.productId} )} Token ID: {scanResult?.ticketId} Email: {scanResult?.purchaserData.email} {scanResult.purchaserData.quantity && ( - - Quantity: {scanResult.purchaserData.quantity} - + Quantity: {scanResult.purchaserData.quantity} )} {scanResult.purchaserData.size && ( Size: {scanResult.purchaserData.size} From c6790d8db65965f633313f3d8263154ede0f7b0a Mon Sep 17 00:00:00 2001 From: Dev Singh Date: Tue, 4 Nov 2025 23:52:17 -0600 Subject: [PATCH 5/6] Fix claiming behavior for multiple tickets --- src/ui/pages/tickets/ScanTickets.page.tsx | 109 ++++++++++++++++------ 1 file changed, 82 insertions(+), 27 deletions(-) diff --git a/src/ui/pages/tickets/ScanTickets.page.tsx b/src/ui/pages/tickets/ScanTickets.page.tsx index 3cba1ae7..545b75de 100644 --- a/src/ui/pages/tickets/ScanTickets.page.tsx +++ b/src/ui/pages/tickets/ScanTickets.page.tsx @@ -13,7 +13,7 @@ import { TextInput, Checkbox, MantineColor, - MantineTheme, // Added for v5 style prop + MantineTheme, } from "@mantine/core"; import { IconAlertCircle, IconCheck, IconCamera } from "@tabler/icons-react"; import jsQR from "jsqr"; @@ -134,9 +134,9 @@ const ScanTicketsPageInternal: React.FC = ({ const [selectedTicketsToClaim, setSelectedTicketsToClaim] = useState( new Set(), ); - // State for bulk success message - const [bulkSuccessMessage, setBulkSuccessMessage] = useState( - null, + // State for bulk success results + const [bulkScanResults, setBulkScanResults] = useState( + [], ); const [ticketItems, setTicketItems] = useState = ({ const [selectedItemFilter, setSelectedItemFilter] = useState( null, ); + // **NEW**: State to hold the mapping of productId to friendly name + const [productNameMap, setProductNameMap] = useState>( + new Map(), + ); const api = useApi("core"); const videoRef = useRef(null); @@ -210,6 +214,11 @@ const ScanTicketsPageInternal: React.FC = ({ const getEmailFromUIN = getEmailFromUINProp || getEmailFromUINDefault; + // **NEW**: Helper function to get the friendly name + const getFriendlyName = (productId: string): string => { + return productNameMap.get(productId) || productId; // Fallback to the ID if not found + }; + const getVideoDevices = async () => { try { const devices = await navigator.mediaDevices.enumerateDevices(); @@ -260,11 +269,17 @@ const ScanTicketsPageInternal: React.FC = ({ const activeMerch: Array<{ value: string; label: string }> = []; const inactiveMerch: Array<{ value: string; label: string }> = []; + // **NEW**: Create the product name map + const newProductMap = new Map(); + const now = new Date(); // Process all tickets if (response.tickets) { response.tickets.forEach((ticket: TicketItem) => { + // **NEW**: Add to map + newProductMap.set(ticket.itemId, ticket.itemName); + const isActive = ticket.itemSalesActive !== false && (typeof ticket.itemSalesActive === "string" @@ -287,6 +302,9 @@ const ScanTicketsPageInternal: React.FC = ({ // Process all merch if (response.merch) { response.merch.forEach((merch: TicketItem) => { + // **NEW**: Add to map + newProductMap.set(merch.itemId, merch.itemName); + const isActive = merch.itemSalesActive !== false && (typeof merch.itemSalesActive === "string" @@ -306,6 +324,9 @@ const ScanTicketsPageInternal: React.FC = ({ }); } + // **NEW**: Set the product map state + setProductNameMap(newProductMap); + // Build grouped data structure for Mantine Select const groups: Array<{ group: string; @@ -521,7 +542,7 @@ const ScanTicketsPageInternal: React.FC = ({ setError(""); setShowModal(false); setManualInput(""); - setBulkSuccessMessage(null); // Clear bulk message + setBulkScanResults([]); // Clear bulk results setSelectedTicketsToClaim(new Set()); // Clear selection // Refocus the manual input field for easy card swiping setTimeout(() => { @@ -760,10 +781,8 @@ const ScanTicketsPageInternal: React.FC = ({ `Failed to claim ${failedClaims.length} ticket(s). First error: ${firstError}`, ); } else if (successfulClaims.length > 0) { - // All succeeded - setBulkSuccessMessage( - `Successfully claimed ${successfulClaims.length} ticket(s).`, - ); + // All succeeded - store results for detailed display + setBulkScanResults(successfulClaims.map((r) => r.value.result)); } // (If successfulClaims.length === 0 and failedClaims.length === 0, nothing was selected, do nothing) @@ -907,8 +926,8 @@ const ScanTicketsPageInternal: React.FC = ({ > {error} - ) : bulkSuccessMessage ? ( - // Bulk Success Message + ) : bulkScanResults.length > 0 ? ( + // Bulk Success Message with Details } @@ -916,8 +935,35 @@ const ScanTicketsPageInternal: React.FC = ({ color="green" variant="filled" > - {bulkSuccessMessage} + + Successfully claimed {bulkScanResults.length} ticket(s)! + + + {bulkScanResults.map((result, index) => ( + + + + Ticket {index + 1} of {bulkScanResults.length} Details: + + Type: {result.type.toLocaleUpperCase()} + {result.purchaserData.productId && ( + + Product:{" "} + {getFriendlyName(result.purchaserData.productId)} + + )} + Email: {result.purchaserData.email} + {result.purchaserData.quantity && ( + Quantity: {result.purchaserData.quantity} + )} + {result.purchaserData.size && ( + Size: {result.purchaserData.size} + )} + + + ))} + @@ -940,7 +986,11 @@ const ScanTicketsPageInternal: React.FC = ({ Ticket Details: Type: {scanResult?.type.toLocaleUpperCase()} {scanResult.purchaserData.productId && ( - Product: {scanResult.purchaserData.productId} + + {/* **MODIFIED** */} + Product:{" "} + {getFriendlyName(scanResult.purchaserData.productId)} + )} Token ID: {scanResult?.ticketId} @@ -991,29 +1041,34 @@ const ScanTicketsPageInternal: React.FC = ({ key={`${ticket.ticketId}-${index}`} p="md" withBorder - // --- FIXED for v5 --- + // --- CLICKABLE CARD LOGIC --- + onClick={() => { + const newSet = new Set(selectedTicketsToClaim); + if (newSet.has(ticket.ticketId)) { + newSet.delete(ticket.ticketId); + } else { + newSet.add(ticket.ticketId); + } + setSelectedTicketsToClaim(newSet); + }} style={(theme: MantineTheme) => ({ borderLeft: `5px solid ${theme.colors.green[6]}`, + cursor: "pointer", + "&:hover": { + backgroundColor: theme.colors.gray[0], + }, })} > { - const newSet = new Set(selectedTicketsToClaim); - if (event.currentTarget.checked) { - newSet.add(ticket.ticketId); - } else { - newSet.delete(ticket.ticketId); - } - setSelectedTicketsToClaim(newSet); - }} + readOnly + tabIndex={-1} // Removed from tab order, card is the control aria-label={`Select ticket ${ticket.ticketId}`} /> - {ticket.type.toUpperCase()} -{" "} - {ticket.purchaserData.productId} + {getFriendlyName(ticket.purchaserData.productId)} Email: {ticket.purchaserData.email} {ticket.purchaserData.quantity && ( @@ -1055,7 +1110,6 @@ const ScanTicketsPageInternal: React.FC = ({ key={`${ticket.ticketId}-${index}`} p="md" withBorder - // --- FIXED for v5 --- style={(theme: MantineTheme) => ({ cursor: "not-allowed", opacity: 0.6, @@ -1064,8 +1118,9 @@ const ScanTicketsPageInternal: React.FC = ({ > + {/* **MODIFIED** */} {ticket.type.toUpperCase()} -{" "} - {ticket.purchaserData.productId} + {getFriendlyName(ticket.purchaserData.productId)} Email: {ticket.purchaserData.email} From 50954e8708c8c03b9a3eb1cc1f60b312628416d0 Mon Sep 17 00:00:00 2001 From: Dev Singh Date: Tue, 4 Nov 2025 23:57:14 -0600 Subject: [PATCH 6/6] Rename slow lambda to HiCpu lambda and increase memory This increase in memory will also increase CPU --- terraform/envs/prod/main.tf | 8 ++++---- terraform/envs/qa/main.tf | 8 ++++---- terraform/modules/frontend/main.tf | 12 ++++++------ terraform/modules/frontend/variables.tf | 4 ++-- terraform/modules/lambdas/main.tf | 26 ++++++++++++------------- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/terraform/envs/prod/main.tf b/terraform/envs/prod/main.tf index 04cc50af..fcc64652 100644 --- a/terraform/envs/prod/main.tf +++ b/terraform/envs/prod/main.tf @@ -71,7 +71,7 @@ module "alarms" { standard_sns_arn = var.GeneralSNSAlertArn all_lambdas = toset([ module.lambdas.core_api_lambda_name, - module.lambdas.core_api_slow_lambda_name, + module.lambdas.core_api_hicpu_lambda_name, module.lambdas.core_sqs_consumer_lambda_name, module.archival.dynamo_archival_lambda_name ]) @@ -114,9 +114,9 @@ module "frontend" { "us-east-2" = module.lambdas.core_function_url "us-west-2" = module.lambdas_usw2.core_function_url } - CoreSlowLambdaHost = { - "us-east-2" = module.lambdas.core_slow_function_url - "us-west-2" = module.lambdas_usw2.core_slow_function_url + CoreHiCpuLambdaHost = { + "us-east-2" = module.lambdas.core_hicpu_function_url + "us-west-2" = module.lambdas_usw2.core_hicpu_function_url } CurrentActiveRegion = var.current_active_region OriginVerifyKey = module.origin_verify.current_origin_verify_key diff --git a/terraform/envs/qa/main.tf b/terraform/envs/qa/main.tf index ec64dbcb..1dcad1a7 100644 --- a/terraform/envs/qa/main.tf +++ b/terraform/envs/qa/main.tf @@ -73,7 +73,7 @@ module "alarms" { standard_sns_arn = var.GeneralSNSAlertArn all_lambdas = toset([ module.lambdas.core_api_lambda_name, - module.lambdas.core_api_slow_lambda_name, + module.lambdas.core_api_hicpu_lambda_name, module.lambdas.core_sqs_consumer_lambda_name, module.archival.dynamo_archival_lambda_name ]) @@ -117,9 +117,9 @@ module "frontend" { "us-east-2" = module.lambdas.core_function_url "us-west-2" = module.lambdas_usw2.core_function_url } - CoreSlowLambdaHost = { - "us-east-2" = module.lambdas.core_slow_function_url - "us-west-2" = module.lambdas_usw2.core_slow_function_url + CoreHiCpuLambdaHost = { + "us-east-2" = module.lambdas.core_hicpu_function_url + "us-west-2" = module.lambdas_usw2.core_hicpu_function_url } CurrentActiveRegion = var.current_active_region OriginVerifyKey = module.origin_verify.current_origin_verify_key diff --git a/terraform/modules/frontend/main.tf b/terraform/modules/frontend/main.tf index 93a8c63d..fb96edea 100644 --- a/terraform/modules/frontend/main.tf +++ b/terraform/modules/frontend/main.tf @@ -1,5 +1,5 @@ locals { - all_regions = keys(var.CoreSlowLambdaHost) + all_regions = keys(var.CoreHiCpuLambdaHost) } data "aws_caller_identity" "current" {} @@ -179,11 +179,11 @@ resource "aws_cloudfront_distribution" "app_cloudfront_distribution" { } } - # Dynamic origins for each region's Slow Lambda function + # Dynamic origins for each region's HiCpu Lambda function dynamic "origin" { - for_each = var.CoreSlowLambdaHost + for_each = var.CoreHiCpuLambdaHost content { - origin_id = "SlowLambdaFunction-${origin.key}" + origin_id = "HiCpuLambdaFunction-${origin.key}" domain_name = origin.value custom_origin_config { http_port = 80 @@ -221,7 +221,7 @@ resource "aws_cloudfront_distribution" "app_cloudfront_distribution" { } ordered_cache_behavior { path_pattern = "/api/v1/syncIdentity" - target_origin_id = "SlowLambdaFunction-${var.CurrentActiveRegion}" + target_origin_id = "HiCpuLambdaFunction-${var.CurrentActiveRegion}" viewer_protocol_policy = "redirect-to-https" allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"] cached_methods = ["GET", "HEAD"] @@ -235,7 +235,7 @@ resource "aws_cloudfront_distribution" "app_cloudfront_distribution" { } ordered_cache_behavior { path_pattern = "/api/v1/users/findUserByUin" - target_origin_id = "SlowLambdaFunction-${var.CurrentActiveRegion}" + target_origin_id = "HiCpuLambdaFunction-${var.CurrentActiveRegion}" viewer_protocol_policy = "redirect-to-https" allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"] cached_methods = ["GET", "HEAD"] diff --git a/terraform/modules/frontend/variables.tf b/terraform/modules/frontend/variables.tf index 0ad6dc45..a7a9398d 100644 --- a/terraform/modules/frontend/variables.tf +++ b/terraform/modules/frontend/variables.tf @@ -8,9 +8,9 @@ variable "CoreLambdaHost" { description = "Map of region to Lambda Function URL host" } -variable "CoreSlowLambdaHost" { +variable "CoreHiCpuLambdaHost" { type = map(string) - description = "Map of region to Slow Lambda Function URL host" + description = "Map of region to HiCpu Lambda Function URL host" } variable "CurrentActiveRegion" { diff --git a/terraform/modules/lambdas/main.tf b/terraform/modules/lambdas/main.tf index dfdc1acb..a96307e2 100644 --- a/terraform/modules/lambdas/main.tf +++ b/terraform/modules/lambdas/main.tf @@ -18,7 +18,7 @@ data "archive_file" "linkry_edge_lambda_code" { locals { core_api_lambda_name = "${var.ProjectId}-main-server" - core_api_slow_lambda_name = "${var.ProjectId}-slow-server" + core_api_hicpu_lambda_name = "${var.ProjectId}-hicpu-server" core_sqs_consumer_lambda_name = "${var.ProjectId}-sqs-consumer" entra_policies = { shared = aws_iam_policy.shared_iam_policy.arn @@ -403,18 +403,18 @@ resource "aws_lambda_function_url" "api_lambda_function_url" { invoke_mode = "RESPONSE_STREAM" } -// Slow lambda - used for monitoring purposes to avoid triggering lamdba latency alarms -resource "aws_lambda_function" "slow_lambda" { +// hicpu lambda - used for monitoring purposes to avoid triggering lamdba latency alarms +resource "aws_lambda_function" "hicpu_lambda" { region = var.region depends_on = [aws_cloudwatch_log_group.api_logs] - function_name = local.core_api_slow_lambda_name + function_name = local.core_api_hicpu_lambda_name role = aws_iam_role.api_role.arn architectures = ["arm64"] handler = "lambda.handler" runtime = "nodejs22.x" filename = data.archive_file.api_lambda_code.output_path timeout = 15 - memory_size = 2048 + memory_size = 4096 // This will get us 2 full CPU cores, which will speed up those cryptographic ops that require this server source_code_hash = data.archive_file.api_lambda_code.output_sha256 logging_config { log_group = aws_cloudwatch_log_group.api_logs.name @@ -433,9 +433,9 @@ resource "aws_lambda_function" "slow_lambda" { } } -resource "aws_lambda_function_url" "slow_api_lambda_function_url" { +resource "aws_lambda_function_url" "hicpu_api_lambda_function_url" { region = var.region - function_name = aws_lambda_function.slow_lambda.function_name + function_name = aws_lambda_function.hicpu_lambda.function_name authorization_type = "NONE" invoke_mode = "RESPONSE_STREAM" } @@ -447,10 +447,10 @@ module "lambda_warmer_main" { is_streaming_lambda = true } -module "lambda_warmer_slow" { +module "lambda_warmer_hicpu" { region = var.region source = "git::https://github.com/acm-uiuc/terraform-modules.git//lambda-warmer?ref=c1a2d3a474a719b0c1e46842e96056478e98c2c7" - function_to_warm = local.core_api_slow_lambda_name + function_to_warm = local.core_api_hicpu_lambda_name is_streaming_lambda = true } @@ -523,16 +523,16 @@ output "core_function_url" { value = replace(replace(aws_lambda_function_url.api_lambda_function_url.function_url, "https://", ""), "/", "") } -output "core_slow_function_url" { - value = replace(replace(aws_lambda_function_url.slow_api_lambda_function_url.function_url, "https://", ""), "/", "") +output "core_hicpu_function_url" { + value = replace(replace(aws_lambda_function_url.hicpu_api_lambda_function_url.function_url, "https://", ""), "/", "") } output "core_api_lambda_name" { value = local.core_api_lambda_name } -output "core_api_slow_lambda_name" { - value = local.core_api_slow_lambda_name +output "core_api_hicpu_lambda_name" { + value = local.core_api_hicpu_lambda_name }