From 613420e5454bad08c69587a5a1c225f5b27673d0 Mon Sep 17 00:00:00 2001 From: Buffden Date: Wed, 8 Apr 2026 11:37:53 -0500 Subject: [PATCH 1/9] applying cors header to the 429 error code upon rate limiting in ngxin prod --- infra/nginx/nginx.prod.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/infra/nginx/nginx.prod.conf b/infra/nginx/nginx.prod.conf index a02e10a..6c05a26 100644 --- a/infra/nginx/nginx.prod.conf +++ b/infra/nginx/nginx.prod.conf @@ -302,6 +302,8 @@ http { # API clients expect JSON — an HTML response breaks their parsing. # ------------------------------------------------------------------- location @rate_limit_error { + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; default_type application/json; return 429 '{"status":429,"error":"Too Many Requests","message":"Rate limit exceeded. Please try again later."}'; } From c2ecd016880e98692c01b04d213daf61e245d378 Mon Sep 17 00:00:00 2001 From: Buffden Date: Fri, 10 Apr 2026 06:02:14 -0500 Subject: [PATCH 2/9] remove short code padding and add creator tracking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Strip leading zeros from base62 short codes (0000GB → GB) for shorter user-facing redirect URLs; update min size in RedirectController from 6 to 1 accordingly Add creator_ip, creator_user_agent, referer, and click_count columns to url_mappings; tracking fields are captured from HTTP request headers at creation time and never exposed in API responses Increment click_count on every successful redirect V2 migration: strips leading zeros from existing rows, relaxes short_code check constraint to {1,32}, adds tracking columns --- .../controller/RedirectController.java | 2 +- .../com/tinyurl/controller/UrlController.java | 14 ++++++- .../tinyurl/encoding/Base62EncoderImpl.java | 8 +--- .../tinyurl/repository/UrlMappingEntity.java | 41 ++++++++++++++++++- .../java/com/tinyurl/service/UrlService.java | 2 +- .../com/tinyurl/service/UrlServiceImpl.java | 10 ++++- .../V2__strip_short_code_leading_zeros.sql | 23 +++++++++++ .../encoding/Base62EncoderImplTest.java | 6 +-- .../tinyurl/service/UrlServiceImplTest.java | 15 +++---- 9 files changed, 97 insertions(+), 24 deletions(-) create mode 100644 tinyurl/src/main/resources/db/migration/V2__strip_short_code_leading_zeros.sql diff --git a/tinyurl/src/main/java/com/tinyurl/controller/RedirectController.java b/tinyurl/src/main/java/com/tinyurl/controller/RedirectController.java index 8f01877..521cca3 100644 --- a/tinyurl/src/main/java/com/tinyurl/controller/RedirectController.java +++ b/tinyurl/src/main/java/com/tinyurl/controller/RedirectController.java @@ -31,7 +31,7 @@ public RedirectController(UrlService urlService, AppProperties appProperties) { @GetMapping("/{shortCode}") public ResponseEntity redirect( @PathVariable - @Size(min = 6, max = 8, message = "INVALID_URL") + @Size(min = 1, max = 8, message = "INVALID_URL") @Pattern(regexp = "^[0-9A-Za-z]+$", message = "INVALID_URL") String shortCode ) { diff --git a/tinyurl/src/main/java/com/tinyurl/controller/UrlController.java b/tinyurl/src/main/java/com/tinyurl/controller/UrlController.java index c1cf91d..b357b61 100644 --- a/tinyurl/src/main/java/com/tinyurl/controller/UrlController.java +++ b/tinyurl/src/main/java/com/tinyurl/controller/UrlController.java @@ -5,6 +5,7 @@ import com.tinyurl.dto.CreateUrlResponse; import com.tinyurl.dto.UrlMapping; import com.tinyurl.service.UrlService; +import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -26,8 +27,17 @@ public UrlController(UrlService urlService, AppProperties appProperties) { } @PostMapping - public ResponseEntity create(@Valid @RequestBody CreateUrlRequest request) { - UrlMapping created = urlService.shortenUrl(request); + public ResponseEntity create( + @Valid @RequestBody CreateUrlRequest request, + HttpServletRequest httpRequest + ) { + String ip = httpRequest.getHeader("X-Forwarded-For") != null + ? httpRequest.getHeader("X-Forwarded-For").split(",")[0].trim() + : httpRequest.getRemoteAddr(); + String userAgent = httpRequest.getHeader("User-Agent"); + String referer = httpRequest.getHeader("Referer"); + + UrlMapping created = urlService.shortenUrl(request, ip, userAgent, referer); String baseUrl = appProperties.baseUrl().endsWith("/") ? appProperties.baseUrl().substring(0, appProperties.baseUrl().length() - 1) : appProperties.baseUrl(); diff --git a/tinyurl/src/main/java/com/tinyurl/encoding/Base62EncoderImpl.java b/tinyurl/src/main/java/com/tinyurl/encoding/Base62EncoderImpl.java index b92528d..94c025e 100644 --- a/tinyurl/src/main/java/com/tinyurl/encoding/Base62EncoderImpl.java +++ b/tinyurl/src/main/java/com/tinyurl/encoding/Base62EncoderImpl.java @@ -7,8 +7,6 @@ public class Base62EncoderImpl implements Base62Encoder { private static final String CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; private static final int BASE = CHARSET.length(); - private static final int MIN_LENGTH = 6; - @Override public String encode(long id) { if (id < 0) { @@ -16,7 +14,7 @@ public String encode(long id) { } if (id == 0) { - return "0".repeat(MIN_LENGTH); + return "0"; } StringBuilder encoded = new StringBuilder(); @@ -28,10 +26,6 @@ public String encode(long id) { value /= BASE; } - while (encoded.length() < MIN_LENGTH) { - encoded.append('0'); - } - return encoded.reverse().toString(); } diff --git a/tinyurl/src/main/java/com/tinyurl/repository/UrlMappingEntity.java b/tinyurl/src/main/java/com/tinyurl/repository/UrlMappingEntity.java index ac8c535..186250d 100644 --- a/tinyurl/src/main/java/com/tinyurl/repository/UrlMappingEntity.java +++ b/tinyurl/src/main/java/com/tinyurl/repository/UrlMappingEntity.java @@ -28,6 +28,18 @@ public class UrlMappingEntity { @Column(name = "has_explicit_expiry", nullable = false) private boolean hasExplicitExpiry; + @Column(name = "creator_ip", length = 45) + private String creatorIp; + + @Column(name = "creator_user_agent", length = 512) + private String creatorUserAgent; + + @Column(name = "referer", length = 2048) + private String referer; + + @Column(name = "click_count", nullable = false) + private long clickCount; + protected UrlMappingEntity() { } @@ -37,7 +49,10 @@ public UrlMappingEntity( String originalUrl, OffsetDateTime createdAt, OffsetDateTime expiresAt, - boolean hasExplicitExpiry + boolean hasExplicitExpiry, + String creatorIp, + String creatorUserAgent, + String referer ) { this.id = id; this.shortCode = shortCode; @@ -45,6 +60,10 @@ public UrlMappingEntity( this.createdAt = createdAt; this.expiresAt = expiresAt; this.hasExplicitExpiry = hasExplicitExpiry; + this.creatorIp = creatorIp; + this.creatorUserAgent = creatorUserAgent; + this.referer = referer; + this.clickCount = 0; } public Long getId() { @@ -71,4 +90,24 @@ public boolean hasExplicitExpiry() { return hasExplicitExpiry; } + public String getCreatorIp() { + return creatorIp; + } + + public String getCreatorUserAgent() { + return creatorUserAgent; + } + + public String getReferer() { + return referer; + } + + public long getClickCount() { + return clickCount; + } + + public void incrementClickCount() { + this.clickCount++; + } + } diff --git a/tinyurl/src/main/java/com/tinyurl/service/UrlService.java b/tinyurl/src/main/java/com/tinyurl/service/UrlService.java index 1ab85ac..fb46de2 100644 --- a/tinyurl/src/main/java/com/tinyurl/service/UrlService.java +++ b/tinyurl/src/main/java/com/tinyurl/service/UrlService.java @@ -5,6 +5,6 @@ import java.util.Optional; public interface UrlService { - UrlMapping shortenUrl(CreateUrlRequest request); + UrlMapping shortenUrl(CreateUrlRequest request, String creatorIp, String creatorUserAgent, String referer); Optional resolveCode(String code); } diff --git a/tinyurl/src/main/java/com/tinyurl/service/UrlServiceImpl.java b/tinyurl/src/main/java/com/tinyurl/service/UrlServiceImpl.java index 4aed844..2065bc6 100644 --- a/tinyurl/src/main/java/com/tinyurl/service/UrlServiceImpl.java +++ b/tinyurl/src/main/java/com/tinyurl/service/UrlServiceImpl.java @@ -30,7 +30,7 @@ public UrlServiceImpl(UrlRepository urlRepository, Base62Encoder base62Encoder, } @Override - public UrlMapping shortenUrl(CreateUrlRequest request) { + public UrlMapping shortenUrl(CreateUrlRequest request, String creatorIp, String creatorUserAgent, String referer) { validateUrl(request.url()); boolean hasExplicitExpiry = request.expiresInDays() != null; int expiresInDays = normalizeExpiry(request.expiresInDays()); @@ -46,7 +46,10 @@ public UrlMapping shortenUrl(CreateUrlRequest request) { request.url(), now, expiresAt, - hasExplicitExpiry + hasExplicitExpiry, + creatorIp, + creatorUserAgent, + referer ); UrlMappingEntity persisted = urlRepository.save(entity); @@ -66,6 +69,9 @@ public Optional resolveCode(String code) { throw new GoneException("This short URL has expired or been removed."); } + entity.incrementClickCount(); + urlRepository.save(entity); + return Optional.of(toDomain(entity)); } diff --git a/tinyurl/src/main/resources/db/migration/V2__strip_short_code_leading_zeros.sql b/tinyurl/src/main/resources/db/migration/V2__strip_short_code_leading_zeros.sql new file mode 100644 index 0000000..7e0d8d0 --- /dev/null +++ b/tinyurl/src/main/resources/db/migration/V2__strip_short_code_leading_zeros.sql @@ -0,0 +1,23 @@ +-- Remove leading zeros from existing short codes, relax the minimum length constraint, +-- and add creator tracking columns. + +-- Strip leading zeros from all existing short codes +UPDATE url_mappings +SET short_code = LTRIM(short_code, '0') +WHERE short_code ~ '^0+.+$'; + +-- Update the format constraint to allow codes as short as 1 character +ALTER TABLE url_mappings + DROP CONSTRAINT chk_short_code_format, + ADD CONSTRAINT chk_short_code_format CHECK (short_code ~ '^[0-9a-zA-Z_-]{1,32}$'); + +-- Add creator tracking columns +-- creator_ip: IPv4 (max 15 chars) or IPv6 (max 45 chars) of the requester +-- creator_user_agent: browser, device, or app that made the request +-- referer: page the user was on when they created the short URL +-- click_count: incremented on every successful redirect +ALTER TABLE url_mappings + ADD COLUMN creator_ip VARCHAR(45) NULL, + ADD COLUMN creator_user_agent VARCHAR(512) NULL, + ADD COLUMN referer VARCHAR(2048) NULL, + ADD COLUMN click_count BIGINT NOT NULL DEFAULT 0; diff --git a/tinyurl/src/test/java/com/tinyurl/encoding/Base62EncoderImplTest.java b/tinyurl/src/test/java/com/tinyurl/encoding/Base62EncoderImplTest.java index 24eb768..7bc1f0d 100644 --- a/tinyurl/src/test/java/com/tinyurl/encoding/Base62EncoderImplTest.java +++ b/tinyurl/src/test/java/com/tinyurl/encoding/Base62EncoderImplTest.java @@ -10,9 +10,9 @@ class Base62EncoderImplTest { private final Base62EncoderImpl encoder = new Base62EncoderImpl(); @Test - void encodeShouldPadToAtLeastSixCharacters() { - assertEquals(6, encoder.encode(1).length()); - assertEquals("000000", encoder.encode(0)); + void encodeShouldNotPadWithLeadingZeros() { + assertEquals("1", encoder.encode(1)); + assertEquals("0", encoder.encode(0)); } @Test diff --git a/tinyurl/src/test/java/com/tinyurl/service/UrlServiceImplTest.java b/tinyurl/src/test/java/com/tinyurl/service/UrlServiceImplTest.java index 5622b7c..845deed 100644 --- a/tinyurl/src/test/java/com/tinyurl/service/UrlServiceImplTest.java +++ b/tinyurl/src/test/java/com/tinyurl/service/UrlServiceImplTest.java @@ -45,7 +45,7 @@ void setUp() { void shortenUrlShouldRejectMalformedUrl() { IllegalArgumentException ex = assertThrows( IllegalArgumentException.class, - () -> service.shortenUrl(new CreateUrlRequest("not-a-url", 30)) + () -> service.shortenUrl(new CreateUrlRequest("not-a-url", 30), null, null, null) ); assertEquals("INVALID_URL", ex.getMessage()); } @@ -54,7 +54,7 @@ void shortenUrlShouldRejectMalformedUrl() { void shortenUrlShouldRejectNonHttpUrl() { IllegalArgumentException ex = assertThrows( IllegalArgumentException.class, - () -> service.shortenUrl(new CreateUrlRequest("ftp://example.com", 30)) + () -> service.shortenUrl(new CreateUrlRequest("ftp://example.com", 30), null, null, null) ); assertEquals("INVALID_URL", ex.getMessage()); } @@ -63,7 +63,7 @@ void shortenUrlShouldRejectNonHttpUrl() { void shortenUrlShouldRejectZeroExpiry() { IllegalArgumentException ex = assertThrows( IllegalArgumentException.class, - () -> service.shortenUrl(new CreateUrlRequest("https://example.com", 0)) + () -> service.shortenUrl(new CreateUrlRequest("https://example.com", 0), null, null, null) ); assertEquals("INVALID_EXPIRY", ex.getMessage()); } @@ -72,7 +72,7 @@ void shortenUrlShouldRejectZeroExpiry() { void shortenUrlShouldRejectTooLargeExpiry() { IllegalArgumentException ex = assertThrows( IllegalArgumentException.class, - () -> service.shortenUrl(new CreateUrlRequest("https://example.com", 3651)) + () -> service.shortenUrl(new CreateUrlRequest("https://example.com", 3651), null, null, null) ); assertEquals("INVALID_EXPIRY", ex.getMessage()); } @@ -84,7 +84,7 @@ void shortenUrlShouldUseDefaultExpiryAndMarkAsNonExplicit() { when(urlRepository.save(any(UrlMappingEntity.class))).thenAnswer(invocation -> invocation.getArgument(0)); OffsetDateTime before = OffsetDateTime.now(ZoneOffset.UTC); - UrlMapping result = service.shortenUrl(new CreateUrlRequest("https://example.com/default", null)); + UrlMapping result = service.shortenUrl(new CreateUrlRequest("https://example.com/default", null), "1.2.3.4", "TestAgent", null); OffsetDateTime after = OffsetDateTime.now(ZoneOffset.UTC); assertEquals("0000Ab", result.shortCode()); @@ -105,7 +105,7 @@ void shortenUrlShouldUseProvidedExpiryAndMarkAsExplicit() { when(urlRepository.save(any(UrlMappingEntity.class))).thenAnswer(invocation -> invocation.getArgument(0)); OffsetDateTime before = OffsetDateTime.now(ZoneOffset.UTC); - UrlMapping result = service.shortenUrl(new CreateUrlRequest("https://example.com/explicit", 30)); + UrlMapping result = service.shortenUrl(new CreateUrlRequest("https://example.com/explicit", 30), "1.2.3.4", "TestAgent", "https://tinyurl.buffden.com/"); OffsetDateTime after = OffsetDateTime.now(ZoneOffset.UTC); assertEquals("0000Ac", result.shortCode()); @@ -132,7 +132,8 @@ void resolveCodeShouldThrowGoneWhenExpired() { "https://example.com/expired", OffsetDateTime.now(ZoneOffset.UTC).minusDays(40), OffsetDateTime.now(ZoneOffset.UTC).minus(1, ChronoUnit.MINUTES), - true + true, + null, null, null ); when(urlRepository.findByShortCode("0000Ad")).thenReturn(Optional.of(expired)); From 36ecf02748199406e49a043436e6b9fae493d0b4 Mon Sep 17 00:00:00 2001 From: Buffden Date: Fri, 10 Apr 2026 06:04:26 -0500 Subject: [PATCH 3/9] gitignore update --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d670515..e4de535 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ ehthumbs.db # Separate repos — managed independently tinyurl-gui/ +docs/insights/ From cc649ea05eef08247489c22aa1fca61a5a6b3541 Mon Sep 17 00:00:00 2001 From: Buffden Date: Fri, 10 Apr 2026 06:26:02 -0500 Subject: [PATCH 4/9] db migration update drop constraint before stripping leading zeros in V2 migration --- .../db/migration/V2__strip_short_code_leading_zeros.sql | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tinyurl/src/main/resources/db/migration/V2__strip_short_code_leading_zeros.sql b/tinyurl/src/main/resources/db/migration/V2__strip_short_code_leading_zeros.sql index 7e0d8d0..ce76e56 100644 --- a/tinyurl/src/main/resources/db/migration/V2__strip_short_code_leading_zeros.sql +++ b/tinyurl/src/main/resources/db/migration/V2__strip_short_code_leading_zeros.sql @@ -1,6 +1,10 @@ -- Remove leading zeros from existing short codes, relax the minimum length constraint, -- and add creator tracking columns. +-- Drop the old constraint first (required min 4 chars) so the UPDATE below can produce shorter codes +ALTER TABLE url_mappings + DROP CONSTRAINT chk_short_code_format; + -- Strip leading zeros from all existing short codes UPDATE url_mappings SET short_code = LTRIM(short_code, '0') @@ -8,7 +12,6 @@ WHERE short_code ~ '^0+.+$'; -- Update the format constraint to allow codes as short as 1 character ALTER TABLE url_mappings - DROP CONSTRAINT chk_short_code_format, ADD CONSTRAINT chk_short_code_format CHECK (short_code ~ '^[0-9a-zA-Z_-]{1,32}$'); -- Add creator tracking columns From 7482ee7ed7ea131d11bbd5dd986573f90f2e74e6 Mon Sep 17 00:00:00 2001 From: Buffden Date: Fri, 24 Apr 2026 23:13:36 -0500 Subject: [PATCH 5/9] night scheduler documentation and diagram --- .../01-scheduler/v1/night-scheduler.md | 120 + .../v1/scheduler-diagram.excalidraw | 2232 +++++++++++++++++ 2 files changed, 2352 insertions(+) create mode 100644 docs/architecture/01-scheduler/v1/night-scheduler.md create mode 100644 docs/architecture/01-scheduler/v1/scheduler-diagram.excalidraw diff --git a/docs/architecture/01-scheduler/v1/night-scheduler.md b/docs/architecture/01-scheduler/v1/night-scheduler.md new file mode 100644 index 0000000..e3f6944 --- /dev/null +++ b/docs/architecture/01-scheduler/v1/night-scheduler.md @@ -0,0 +1,120 @@ +# Night Scheduler — v1 + +> Stop EC2 and RDS every night. Start them back on weekdays. Zero idle compute cost overnight and all weekend. + +--- + +## Overview + +Both projects are portfolio and demo workloads. No real users visit at 2 AM on a Sunday. Running full production infrastructure around the clock for that audience is waste, not reliability. + +A Lambda function triggered by EventBridge Scheduler stops all EC2 instances and RDS every night, and starts them back on weekday mornings. Weekends stay fully off. + +**Result:** 60 hours of zero compute cost per week. ~22% reduction on the monthly AWS bill. The scheduler itself costs nothing — all five supporting services stay within the AWS free tier at this invocation rate. + +--- + +## Schedule + +| Event | Time | Days | +| --- | --- | --- | +| Stop all | 11:00 PM | Every day | +| Start all | 8:00 AM | Monday–Friday only | + +Weekend behavior: instances stop Friday at 11 PM and do not start again until Monday at 8 AM. + +--- + +## Architecture + +See `scheduler-diagram.excalidraw` in this folder for the visual. + +``` +IAM Role IAM Role +(EventBridge → (Lambda execution: + invoke Lambda only) EC2 + RDS stop/start only) + │ │ + ▼ │ +EventBridge Scheduler EventBridge Scheduler │ + (Stop — nightly) (Start — weekdays) │ + │ │ │ + └──────────────┬───────────┘ │ + ▼ │ + Lambda Function ◄───────────────────┘ + (Stop / start logic) + │ + ┌─────────────┼─────────────┐ + ▼ ▼ ▼ + EC2 (EMS) EC2 (TinyURL) RDS (TinyURL) + + │ + On any result + ┌──────────┴──────────┐ + ▼ ▼ + CloudWatch Logs On Lambda error (two independent paths) + (every invocation) │ │ + failed event Lambda error metric + payload │ + │ CloudWatch Alarm + SQS Dead Letter │ + Queue (replay) SNS Topic + │ + Email Alert +``` + +--- + +## Why Each Component Exists + +### EventBridge Scheduler + +The scheduling layer. Fires the Lambda on a cron expression with timezone awareness — no UTC offset arithmetic, no drift. Two separate schedules: one for stop, one for start. Each passes an action payload to Lambda so the same function handles both paths. + +Used over the older EventBridge Rules because Scheduler has a persistent schedule store, supports named groups, and is the current AWS standard for this pattern. + +### Lambda + +Runs the stop/start logic. No servers, no idle cost. Receives the action from EventBridge, calls the EC2 and RDS APIs, logs the result, and exits. Execution takes a few seconds per invocation. + +The function is stateless and has no side effects beyond stopping or starting the three resources it is scoped to. + +### IAM Role + +Least-privilege. The role attached to Lambda can stop and start only the specific EC2 instances and RDS instance it manages — nothing else in the account. A bug or misconfiguration in the function cannot affect any other resource. + +A separate role is attached to EventBridge Scheduler, scoped to invoking only this Lambda function. + +### SQS Dead Letter Queue + +If Lambda throws an unhandled exception, the failed event payload is routed to the DLQ instead of disappearing. Without it, a failed stop invocation produces no record — the instances stay on, the bill accumulates, and there is nothing to investigate. The DLQ ensures every failure is captured and can be replayed once the root cause is fixed. + +### CloudWatch Logs + +Every invocation writes structured logs. Full execution history — which instances were targeted, what state transitions occurred, any warnings — without needing SSH access to anything. + +### CloudWatch Alarm + SNS + +The alarm watches the Lambda error metric. If Lambda errors, the alarm fires and publishes to an SNS topic which sends an email alert. + +This matters because a missed stop that goes unnoticed is just a delayed line item on the next bill. The alert closes that gap — failure is visible immediately, not at the end of the month. + +--- + +## Cost + +All five services stay within the AWS free tier at this invocation rate. The scheduler itself adds nothing to the bill while saving ~$18/month in EC2 and RDS compute hours. + +Note: the ALB charges 24/7 regardless of whether the EC2 is running. Scheduler savings apply only to EC2 and RDS instance hours. + +--- + +## Design Decisions + +**Why not GitHub Actions scheduled workflows?** +Simpler to implement, but depends on GitHub availability. If GitHub has an incident during the nightly stop window, instances stay on. An AWS-native scheduler is more reliable for a billing-sensitive job. + +**Why Lambda over EventBridge direct SDK targets?** +EventBridge Scheduler can invoke EC2 and RDS APIs directly without Lambda. The Lambda approach was chosen because it adds observability (structured logs, DLQ, error metrics) that direct targets do not provide. For an unattended nightly job, knowing what happened matters more than removing one service from the stack. + +**Why not always-on infrastructure?** +These are portfolio projects. The scheduler is a deliberate trade-off: lower availability in exchange for lower cost. Recruiters and interviewers are not visiting at 2 AM on a Sunday. If the service is needed outside the window, it can be started manually in under a minute. diff --git a/docs/architecture/01-scheduler/v1/scheduler-diagram.excalidraw b/docs/architecture/01-scheduler/v1/scheduler-diagram.excalidraw new file mode 100644 index 0000000..76630e7 --- /dev/null +++ b/docs/architecture/01-scheduler/v1/scheduler-diagram.excalidraw @@ -0,0 +1,2232 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://marketplace.visualstudio.com/items?itemName=pomdtr.excalidraw-editor", + "elements": [ + { + "id": "eb-stop", + "type": "rectangle", + "x": 77.76972395042748, + "y": 33.34090049880999, + "width": 240, + "height": 80, + "angle": 0, + "strokeColor": "#7c3aed", + "backgroundColor": "#e9d5ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": { + "type": 3 + }, + "groupIds": [], + "frameId": null, + "seed": 101, + "version": 302, + "versionNonce": 187535069, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "eb-stop-t" + }, + { + "id": "arrow-eb-stop-lambda", + "type": "arrow" + } + ], + "updated": 1777090156747, + "link": null, + "locked": false, + "index": "a0" + }, + { + "id": "eb-stop-t", + "type": "text", + "x": 122.19081312279076, + "y": 47.09090049880999, + "width": 151.15782165527344, + "height": 52.5, + "angle": 0, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 102, + "version": 303, + "versionNonce": 1040151315, + "isDeleted": false, + "boundElements": [], + "containerId": "eb-stop", + "updated": 1777090156748, + "link": null, + "locked": false, + "text": "EventBridge Scheduler\nStop — 11 PM daily\ncron(0 4 * * ? *)", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "originalText": "EventBridge Scheduler\nStop — 11 PM daily\ncron(0 4 * * ? *)", + "lineHeight": 1.25, + "index": "a1", + "autoResize": true + }, + { + "id": "eb-start", + "type": "rectangle", + "x": 333.39924038506246, + "y": 32.0351198327821, + "width": 240, + "height": 80, + "angle": 0, + "strokeColor": "#7c3aed", + "backgroundColor": "#e9d5ff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": { + "type": 3 + }, + "groupIds": [], + "frameId": null, + "seed": 103, + "version": 144, + "versionNonce": 976436125, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "eb-start-t" + }, + { + "id": "arrow-eb-start-lambda", + "type": "arrow" + } + ], + "updated": 1777090156748, + "link": null, + "locked": false, + "index": "a2" + }, + { + "id": "eb-start-t", + "type": "text", + "x": 364.36630428887105, + "y": 45.7851198327821, + "width": 178.0658721923828, + "height": 52.5, + "angle": 0, + "strokeColor": "#4c1d95", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 104, + "version": 145, + "versionNonce": 238422611, + "isDeleted": false, + "boundElements": [], + "containerId": "eb-start", + "updated": 1777090156748, + "link": null, + "locked": false, + "text": "EventBridge Scheduler\nStart — 7 AM Mon–Fri\ncron(0 12 ? * MON-FRI *)", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "originalText": "EventBridge Scheduler\nStart — 7 AM Mon–Fri\ncron(0 12 ? * MON-FRI *)", + "lineHeight": 1.25, + "index": "a3", + "autoResize": true + }, + { + "id": "lambda", + "type": "rectangle", + "x": 205.00710635565156, + "y": 179.77970297480005, + "width": 240, + "height": 100, + "angle": 0, + "strokeColor": "#ea580c", + "backgroundColor": "#fed7aa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": { + "type": 3 + }, + "groupIds": [], + "frameId": null, + "seed": 105, + "version": 29, + "versionNonce": 532985949, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "lambda-t" + }, + { + "id": "arrow-eb-stop-lambda", + "type": "arrow" + }, + { + "id": "arrow-lambda-ec2ems", + "type": "arrow" + }, + { + "id": "arrow-eb-start-lambda", + "type": "arrow" + }, + { + "id": "arrow-lambda-ec2tinyurl", + "type": "arrow" + }, + { + "id": "arrow-lambda-iam", + "type": "arrow" + }, + { + "id": "arrow-lambda-rds", + "type": "arrow" + } + ], + "updated": 1777090156748, + "link": null, + "locked": false, + "index": "a4" + }, + { + "id": "lambda-t", + "type": "text", + "x": 213.7467380084836, + "y": 189.15470297480005, + "width": 222.52073669433594, + "height": 81.25, + "angle": 0, + "strokeColor": "#7c2d12", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 106, + "version": 12, + "versionNonce": 1217099187, + "isDeleted": false, + "boundElements": [], + "containerId": "lambda", + "updated": 1777090156751, + "link": null, + "locked": false, + "text": "Lambda Function\nPython / boto3\nstop_instances / start_instances\nstop_db_instance /\nstart_db_instance", + "fontSize": 13, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "originalText": "Lambda Function\nPython / boto3\nstop_instances / start_instances\nstop_db_instance / start_db_instance", + "lineHeight": 1.25, + "index": "a5", + "autoResize": true + }, + { + "id": "iam", + "type": "rectangle", + "x": 498.0789992507705, + "y": 171.71647894007057, + "width": 240, + "height": 100.23918180687508, + "angle": 0, + "strokeColor": "#dc2626", + "backgroundColor": "#fecaca", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": { + "type": 3 + }, + "groupIds": [], + "frameId": null, + "seed": 107, + "version": 126, + "versionNonce": 1884697341, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "iam-t" + }, + { + "id": "arrow-lambda-iam", + "type": "arrow" + } + ], + "updated": 1777090156751, + "link": null, + "locked": false, + "index": "a6" + }, + { + "id": "iam-t", + "type": "text", + "x": 560.2095763381728, + "y": 189.3360698435081, + "width": 115.73884582519531, + "height": 65, + "angle": 0, + "strokeColor": "#7f1d1d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 108, + "version": 127, + "versionNonce": 1750721779, + "isDeleted": false, + "boundElements": [], + "containerId": "iam", + "updated": 1777090156752, + "link": null, + "locked": false, + "text": "IAM Role\nLeast-privilege\nScoped to specific\ninstance ARNs", + "fontSize": 13, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "originalText": "IAM Role\nLeast-privilege\nScoped to specific\ninstance ARNs", + "lineHeight": 1.25, + "index": "a7", + "autoResize": true + }, + { + "id": "ec2-ems", + "type": "rectangle", + "x": 95.6015954260049, + "y": 322.30010428837204, + "width": 126.80416244779144, + "height": 80, + "angle": 0, + "strokeColor": "#16a34a", + "backgroundColor": "#bbf7d0", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": { + "type": 3 + }, + "groupIds": [], + "frameId": null, + "seed": 109, + "version": 610, + "versionNonce": 1314478013, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "ec2-ems-t" + }, + { + "id": "arrow-lambda-ec2ems", + "type": "arrow" + } + ], + "updated": 1777090156752, + "link": null, + "locked": false, + "index": "a8" + }, + { + "id": "ec2-ems-t", + "type": "text", + "x": 114.589217421385, + "y": 337.92510428837204, + "width": 88.82891845703125, + "height": 48.75, + "angle": 0, + "strokeColor": "#14532d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 110, + "version": 601, + "versionNonce": 1212515379, + "isDeleted": false, + "boundElements": [], + "containerId": "ec2-ems", + "updated": 1777090156752, + "link": null, + "locked": false, + "text": "EC2 Instance\nems-prod-app\nt2.micro", + "fontSize": 13, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "originalText": "EC2 Instance\nems-prod-app\nt2.micro", + "lineHeight": 1.25, + "index": "a9", + "autoResize": true + }, + { + "id": "ec2-tinyurl", + "type": "rectangle", + "x": 268.14508011751025, + "y": 321.93606882590683, + "width": 114.33911648841922, + "height": 80, + "angle": 0, + "strokeColor": "#16a34a", + "backgroundColor": "#bbf7d0", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": { + "type": 3 + }, + "groupIds": [], + "frameId": null, + "seed": 111, + "version": 654, + "versionNonce": 1810517117, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "ec2-tinyurl-t" + }, + { + "id": "arrow-lambda-ec2tinyurl", + "type": "arrow" + } + ], + "updated": 1777090156752, + "link": null, + "locked": false, + "index": "aA" + }, + { + "id": "ec2-tinyurl-t", + "type": "text", + "x": 280.90017913320423, + "y": 337.56106882590683, + "width": 88.82891845703125, + "height": 48.75, + "angle": 0, + "strokeColor": "#14532d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 112, + "version": 649, + "versionNonce": 113398643, + "isDeleted": false, + "boundElements": [], + "containerId": "ec2-tinyurl", + "updated": 1777090156753, + "link": null, + "locked": false, + "text": "EC2 Instance\ntinyurl-prod\nt3.micro", + "fontSize": 13, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "originalText": "EC2 Instance\ntinyurl-prod\nt3.micro", + "lineHeight": 1.25, + "index": "aB", + "autoResize": true + }, + { + "id": "rds", + "type": "rectangle", + "x": 432.8104644374662, + "y": 320.66159109468305, + "width": 128.6567497576932, + "height": 80, + "angle": 0, + "strokeColor": "#0284c7", + "backgroundColor": "#bae6fd", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": { + "type": 3 + }, + "groupIds": [], + "frameId": null, + "seed": 113, + "version": 571, + "versionNonce": 2077561149, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "rds-t" + }, + { + "id": "arrow-lambda-rds", + "type": "arrow" + } + ], + "updated": 1777090156753, + "link": null, + "locked": false, + "index": "aC" + }, + { + "id": "rds-t", + "type": "text", + "x": 443.3253932713909, + "y": 336.28659109468305, + "width": 107.62689208984375, + "height": 48.75, + "angle": 0, + "strokeColor": "#0c4a6e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 114, + "version": 568, + "versionNonce": 893670067, + "isDeleted": false, + "boundElements": [], + "containerId": "rds", + "updated": 1777090156753, + "link": null, + "locked": false, + "text": "RDS PostgreSQL\ntinyurl-prod\ndb.t4g.micro", + "fontSize": 13, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "originalText": "RDS PostgreSQL\ntinyurl-prod\ndb.t4g.micro", + "lineHeight": 1.25, + "index": "aD", + "autoResize": true + }, + { + "id": "cw-logs", + "type": "rectangle", + "x": 786.9700048940803, + "y": 223.34318203526698, + "width": 134.87677588279962, + "height": 80.09384475974616, + "angle": 0, + "strokeColor": "#2563eb", + "backgroundColor": "#bfdbfe", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": { + "type": 3 + }, + "groupIds": [], + "frameId": null, + "seed": 115, + "version": 1078, + "versionNonce": 1004266579, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "cw-logs-t" + }, + { + "id": "gISw8QyTtviZvSXZnXi_U", + "type": "arrow" + } + ], + "updated": 1777090092412, + "link": null, + "locked": false, + "index": "aE" + }, + { + "id": "cw-logs-t", + "type": "text", + "x": 800.1594456919253, + "y": 230.89010441514006, + "width": 108.49789428710938, + "height": 65, + "angle": 0, + "strokeColor": "#1e3a8a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 116, + "version": 1069, + "versionNonce": 639754739, + "isDeleted": false, + "boundElements": [], + "containerId": "cw-logs", + "updated": 1777090092412, + "link": null, + "locked": false, + "text": "CloudWatch Logs\nFull execution\nhistory\n30-day retention", + "fontSize": 13, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "originalText": "CloudWatch Logs\nFull execution history\n30-day retention", + "lineHeight": 1.25, + "index": "aF", + "autoResize": true + }, + { + "id": "cw-alarm", + "type": "rectangle", + "x": 951.0631712777617, + "y": 238.42462258218802, + "width": 200.3190560721608, + "height": 80, + "angle": 0, + "strokeColor": "#059669", + "backgroundColor": "#a7f3d0", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": { + "type": 3 + }, + "groupIds": [], + "frameId": null, + "seed": 119, + "version": 1427, + "versionNonce": 1035625277, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "cw-alarm-t" + }, + { + "id": "B3P9vgExjEeGVuApy8QZj", + "type": "arrow" + }, + { + "id": "arrow-dlq-alarm", + "type": "arrow" + } + ], + "updated": 1777090166962, + "link": null, + "locked": false, + "index": "aI" + }, + { + "id": "cw-alarm-t", + "type": "text", + "x": 991.0977527196039, + "y": 254.04962258218802, + "width": 120.24989318847656, + "height": 48.75, + "angle": 0, + "strokeColor": "#064e3b", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 120, + "version": 1418, + "versionNonce": 375714717, + "isDeleted": false, + "boundElements": [], + "containerId": "cw-alarm", + "updated": 1777090166962, + "link": null, + "locked": false, + "text": "CloudWatch Alarm\nLambda errors > 0\n5-minute window", + "fontSize": 13, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "originalText": "CloudWatch Alarm\nLambda errors > 0\n5-minute window", + "lineHeight": 1.25, + "index": "aJ", + "autoResize": true + }, + { + "id": "sns", + "type": "rectangle", + "x": 952.429381211985, + "y": 363.9233979880932, + "width": 199.12811251012567, + "height": 80, + "angle": 0, + "strokeColor": "#db2777", + "backgroundColor": "#fbcfe8", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": { + "type": 3 + }, + "groupIds": [], + "frameId": null, + "seed": 121, + "version": 1566, + "versionNonce": 311712957, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "sns-t" + }, + { + "id": "B3P9vgExjEeGVuApy8QZj", + "type": "arrow" + }, + { + "id": "arrow-sns-email", + "type": "arrow" + } + ], + "updated": 1777090166963, + "link": null, + "locked": false, + "index": "aK" + }, + { + "id": "sns-t", + "type": "text", + "x": 982.2095095495672, + "y": 379.5483979880932, + "width": 139.56785583496094, + "height": 48.75, + "angle": 0, + "strokeColor": "#831843", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 122, + "version": 1559, + "versionNonce": 12827933, + "isDeleted": false, + "boundElements": [], + "containerId": "sns", + "updated": 1777090166963, + "link": null, + "locked": false, + "text": "SNS Topic\nAlert channel\nEmail / Slack webhook", + "fontSize": 13, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "originalText": "SNS Topic\nAlert channel\nEmail / Slack webhook", + "lineHeight": 1.25, + "index": "aL", + "autoResize": true + }, + { + "id": "email", + "type": "rectangle", + "x": 947.0692079768228, + "y": 495.0473088804778, + "width": 204.79791564112764, + "height": 70, + "angle": 0, + "strokeColor": "#4b5563", + "backgroundColor": "#e5e7eb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": { + "type": 3 + }, + "groupIds": [], + "frameId": null, + "seed": 123, + "version": 1511, + "versionNonce": 736466493, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "email-t" + }, + { + "id": "arrow-sns-email", + "type": "arrow" + } + ], + "updated": 1777090166963, + "link": null, + "locked": false, + "index": "aM" + }, + { + "id": "email-t", + "type": "text", + "x": 957.2202943984607, + "y": 513.7973088804778, + "width": 184.49574279785156, + "height": 32.5, + "angle": 0, + "strokeColor": "#111827", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 124, + "version": 1510, + "versionNonce": 514967197, + "isDeleted": false, + "boundElements": [], + "containerId": "email", + "updated": 1777090166963, + "link": null, + "locked": false, + "text": "Email Alert\nScheduler failure notification", + "fontSize": 13, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "originalText": "Email Alert\nScheduler failure notification", + "lineHeight": 1.25, + "index": "aN", + "autoResize": true + }, + { + "id": "arrow-eb-stop-lambda", + "type": "arrow", + "x": 223.4609186681424, + "y": 117.66681160825834, + "width": 56.44333239715675, + "height": 58.18662119296411, + "angle": 0, + "strokeColor": "#7c3aed", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 201, + "version": 685, + "versionNonce": 1843766781, + "isDeleted": false, + "boundElements": [], + "updated": 1777090156753, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 28.89349012854666 + ], + [ + 56.44333239715675, + 28.89349012854666 + ], + [ + 56.44333239715675, + 58.18662119296411 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "eb-stop", + "fixedPoint": [ + 0.6070466446571455, + 1.0540738888681045 + ], + "focus": 0, + "gap": 0 + }, + "endBinding": { + "elementId": "lambda", + "fixedPoint": [ + 0.3120714362901983, + -0.03926270173577592 + ], + "focus": 0, + "gap": 0 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "index": "aO", + "elbowed": true, + "fixedSegments": null, + "startIsSpecial": null, + "endIsSpecial": null + }, + { + "id": "arrow-eb-start-lambda", + "type": "arrow", + "x": 436.5851044893495, + "y": 116.7147211194524, + "width": 72.1531195842, + "height": 59.025699977247854, + "angle": 0, + "strokeColor": "#7c3aed", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 202, + "version": 403, + "versionNonce": 153977939, + "isDeleted": false, + "boundElements": [], + "updated": 1777090156753, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 29.192690284338653 + ], + [ + -72.1531195842, + 29.192690284338653 + ], + [ + -72.1531195842, + 59.025699977247854 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "eb-start", + "fixedPoint": [ + 0.42994110043452927, + 1.0584950160833784 + ], + "focus": 0, + "gap": 0 + }, + "endBinding": { + "elementId": "lambda", + "fixedPoint": [ + 0.6642703272895747, + -0.040392818780997854 + ], + "focus": 0, + "gap": 0 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "index": "aP", + "elbowed": true, + "fixedSegments": null, + "startIsSpecial": null, + "endIsSpecial": null + }, + { + "id": "arrow-lambda-ec2ems", + "type": "arrow", + "x": 259.4690417343513, + "y": 282.9290849507515, + "width": 127.05558912727855, + "height": 35.08433261696791, + "angle": 0, + "strokeColor": "#16a34a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 203, + "version": 885, + "versionNonce": 228187741, + "isDeleted": false, + "boundElements": [], + "updated": 1777090156753, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 11.287930251280102 + ], + [ + -127.05558912727855, + 11.287930251280102 + ], + [ + -127.05558912727855, + 35.08433261696791 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "lambda", + "fixedPoint": [ + 0.22692473074458236, + 1.0314938197595143 + ], + "focus": 0, + "gap": 0 + }, + "endBinding": { + "elementId": "ec2-ems", + "fixedPoint": [ + 0.2903048012814584, + -0.05358358400815817 + ], + "focus": 0, + "gap": 0 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "index": "aQ", + "elbowed": true, + "fixedSegments": [ + { + "index": 2, + "start": [ + 0, + 11.287930251280102 + ], + "end": [ + -127.05558912727855, + 11.287930251280102 + ] + } + ], + "startIsSpecial": false, + "endIsSpecial": false + }, + { + "id": "arrow-lambda-ec2tinyurl", + "type": "arrow", + "x": 324.90710635565154, + "y": 284.77970297480005, + "width": 0.3075320060682998, + "height": 32.156365851106784, + "angle": 0, + "strokeColor": "#16a34a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 204, + "version": 1037, + "versionNonce": 406815219, + "isDeleted": false, + "boundElements": [], + "updated": 1777090156753, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.3075320060682998, + 32.156365851106784 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "lambda", + "fixedPoint": [ + 0.4995833333333332, + 1.05 + ], + "focus": 0, + "gap": 0 + }, + "endBinding": { + "elementId": "ec2-tinyurl", + "fixedPoint": [ + 0.4991254086696557, + -0.0625 + ], + "focus": 0, + "gap": 0 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "index": "aR", + "elbowed": true, + "fixedSegments": null, + "startIsSpecial": null, + "endIsSpecial": null + }, + { + "id": "arrow-lambda-rds", + "type": "arrow", + "x": 389.0391566445468, + "y": 282.97477349263994, + "width": 116.07282155163557, + "height": 32.763756291454285, + "angle": 0, + "strokeColor": "#0284c7", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 205, + "version": 744, + "versionNonce": 786959037, + "isDeleted": false, + "boundElements": [], + "updated": 1777090156753, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 15.158019856357953 + ], + [ + 116.07282155163557, + 15.158019856357953 + ], + [ + 116.07282155163557, + 32.763756291454285 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "lambda", + "focus": 0.171903875150052, + "gap": 1, + "fixedPoint": [ + 0.766800209537063, + 1.0319507051783985 + ] + }, + "endBinding": { + "elementId": "rds", + "fixedPoint": [ + 0.5619721770904819, + -0.06153826638236026 + ], + "focus": 0, + "gap": 0 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "index": "aS", + "elbowed": true, + "fixedSegments": [ + { + "index": 2, + "start": [ + 0, + 15.158019856357953 + ], + "end": [ + 116.07282155163557, + 15.158019856357953 + ] + } + ], + "startIsSpecial": false, + "endIsSpecial": false + }, + { + "id": "arrow-dlq-alarm", + "type": "arrow", + "x": 1134.5639491452682, + "y": 151.08669521218727, + "width": 150.87963997272823, + "height": 83.39824799943906, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 208, + "version": 3806, + "versionNonce": 1961390173, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "XohlLLkCprrVSNZlolUaN" + } + ], + "updated": 1777090166963, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -81.5198748794337, + 0 + ], + [ + -81.5198748794337, + 53.30910079344258 + ], + [ + -150.87963997272823, + 53.30910079344258 + ], + [ + -150.87963997272823, + 83.39824799943906 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "-egso4hRYhx2q8JXxgDIv", + "fixedPoint": [ + -0.029859386566317828, + 0.4989478844065027 + ], + "focus": 0, + "gap": 0 + }, + "endBinding": { + "elementId": "cw-alarm", + "fixedPoint": [ + 0.16284590460044485, + -0.049245992132021146 + ], + "focus": 0, + "gap": 0 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "index": "aV", + "elbowed": true, + "fixedSegments": [ + { + "index": 2, + "start": [ + -81.5198748794337, + 0 + ], + "end": [ + -81.5198748794337, + 53.30910079344258 + ] + }, + { + "index": 3, + "start": [ + -81.5198748794337, + 53.30910079344258 + ], + "end": [ + -150.87963997272823, + 53.30910079344258 + ] + } + ], + "startIsSpecial": false, + "endIsSpecial": false + }, + { + "id": "XohlLLkCprrVSNZlolUaN", + "type": "text", + "x": 658.1502765512571, + "y": 665.5734038418145, + "width": 107.05589294433594, + "height": 40, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aVO", + "roundness": null, + "seed": 1418495507, + "version": 31, + "versionNonce": 2049525309, + "isDeleted": false, + "boundElements": null, + "updated": 1777089626738, + "link": null, + "locked": false, + "text": "Lambda error \nmetric", + "fontSize": 16, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "arrow-dlq-alarm", + "originalText": "Lambda error \nmetric", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "B3P9vgExjEeGVuApy8QZj", + "type": "arrow", + "x": 1129.3854803168672, + "y": 321.55582969282483, + "width": 142.7131893216697, + "height": 38.64828087524643, + "angle": 0, + "strokeColor": "#c2255c", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 421514276, + "version": 4969, + "versionNonce": 244256797, + "isDeleted": false, + "boundElements": [], + "updated": 1777090167401, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 17.999552639362264 + ], + [ + -142.7131893216697, + 17.999552639362264 + ], + [ + -142.7131893216697, + 38.64828087524643 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "cw-alarm", + "fixedPoint": [ + 0.890191440273503, + 1.0391400888829607 + ], + "focus": 0, + "gap": 0 + }, + "endBinding": { + "elementId": "sns", + "fixedPoint": [ + 0.17196421615994226, + -0.04649109275027428 + ], + "focus": 0, + "gap": 0 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "index": "aVl", + "elbowed": true, + "fixedSegments": [ + { + "index": 2, + "start": [ + 0, + 17.999552639362264 + ], + "end": [ + -142.7131893216697, + 17.999552639362264 + ] + } + ], + "startIsSpecial": false, + "endIsSpecial": false + }, + { + "id": "arrow-sns-email", + "type": "arrow", + "x": 1117.9807843399715, + "y": 446.6405255890901, + "width": 134.1567003240034, + "height": 45.61549195771727, + "angle": 0, + "strokeColor": "#4b5563", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 210, + "version": 4736, + "versionNonce": 1171326077, + "isDeleted": false, + "boundElements": [], + "updated": 1777090167402, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 20.14179376467996 + ], + [ + -134.1567003240034, + 20.14179376467996 + ], + [ + -134.1567003240034, + 45.61549195771727 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "sns", + "fixedPoint": [ + 0.8313813707221688, + 1.0339640950124618 + ], + "focus": 0, + "gap": 0 + }, + "endBinding": { + "elementId": "email", + "fixedPoint": [ + 0.17946899471160518, + -0.03987559048100593 + ], + "focus": 0, + "gap": 0 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "index": "aX", + "elbowed": true, + "fixedSegments": [ + { + "index": 2, + "start": [ + 0, + 20.14179376467996 + ], + "end": [ + -134.1567003240034, + 20.14179376467996 + ] + } + ], + "startIsSpecial": false, + "endIsSpecial": false + }, + { + "id": "arrow-lambda-iam", + "type": "arrow", + "x": 449.9560217085917, + "y": 247.77899948666914, + "width": 43.22087344086026, + "height": 51.02903359193152, + "angle": 0, + "strokeColor": "#dc2626", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 0, + "opacity": 100, + "roundness": null, + "groupIds": [], + "frameId": null, + "seed": 211, + "version": 222, + "versionNonce": 461425555, + "isDeleted": false, + "boundElements": [], + "updated": 1777090156753, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 21.587031094619306, + 0 + ], + [ + 21.587031094619306, + -51.02903359193152 + ], + [ + 43.22087344086026, + -51.02903359193152 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "lambda", + "fixedPoint": [ + 1.0206204806372507, + 0.6799929651186909 + ], + "focus": 0, + "gap": 0 + }, + "endBinding": { + "elementId": "iam", + "fixedPoint": [ + -0.02042543375549381, + 0.24973754277940519 + ], + "focus": 0, + "gap": 0 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "index": "aY", + "elbowed": true, + "fixedSegments": null, + "startIsSpecial": null, + "endIsSpecial": null + }, + { + "id": "h1m_RV498yMoqOf4Ff5O7", + "type": "rectangle", + "x": 923.2398154270375, + "y": 27.82758507560237, + "width": 194.39323724617003, + "height": 65.50335463683223, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffec99", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ai", + "roundness": { + "type": 3 + }, + "seed": 2145051165, + "version": 632, + "versionNonce": 80809437, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "xc_N7Hc9mAD4It6adMwtU" + }, + { + "id": "5wHYcPQUcNs3ZKkcJPLgL", + "type": "arrow" + }, + { + "id": "gISw8QyTtviZvSXZnXi_U", + "type": "arrow" + } + ], + "updated": 1777090146029, + "link": null, + "locked": false + }, + { + "id": "xc_N7Hc9mAD4It6adMwtU", + "type": "text", + "x": 955.2064764695563, + "y": 48.079262394018485, + "width": 130.4599151611328, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aj", + "roundness": null, + "seed": 346877373, + "version": 579, + "versionNonce": 646793789, + "isDeleted": false, + "boundElements": null, + "updated": 1777090146029, + "link": null, + "locked": false, + "text": "On any result", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "h1m_RV498yMoqOf4Ff5O7", + "originalText": "On any result", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "gISw8QyTtviZvSXZnXi_U", + "type": "arrow", + "x": 918.2398154270375, + "y": 60.47926239401849, + "width": 63.93142259155741, + "height": 157.85805434376434, + "angle": 0, + "strokeColor": "#1971c2", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ak", + "roundness": null, + "seed": 1970273939, + "version": 2307, + "versionNonce": 1889771261, + "isDeleted": false, + "boundElements": null, + "updated": 1777090146029, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -63.93142259155741, + 0 + ], + [ + -63.93142259155741, + 157.85805434376434 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "h1m_RV498yMoqOf4Ff5O7", + "fixedPoint": [ + -0.02572105938885233, + 0.4984733606308498 + ], + "focus": 0, + "gap": 0 + }, + "endBinding": { + "elementId": "cw-logs", + "fixedPoint": [ + 0.499258582514703, + -0.0625 + ], + "focus": 0, + "gap": 1 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": true, + "fixedSegments": null, + "startIsSpecial": null, + "endIsSpecial": null + }, + { + "id": "5wHYcPQUcNs3ZKkcJPLgL", + "type": "arrow", + "x": 1122.6330526732074, + "y": 60.47926239401849, + "width": 100.55666205158764, + "height": 38.18413755572382, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "al", + "roundness": null, + "seed": 1987311635, + "version": 1868, + "versionNonce": 1380121245, + "isDeleted": false, + "boundElements": [], + "updated": 1777090146029, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 100.55666205158764, + 0 + ], + [ + 100.55666205158764, + 38.18413755572382 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "h1m_RV498yMoqOf4Ff5O7", + "fixedPoint": [ + 1.025721059388852, + 0.4984733606308498 + ], + "focus": 0, + "gap": 0 + }, + "endBinding": { + "elementId": "-egso4hRYhx2q8JXxgDIv", + "fixedPoint": [ + 0.4994028122686735, + -0.05260577967487059 + ], + "focus": 0, + "gap": 0 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": true, + "fixedSegments": null, + "startIsSpecial": null, + "endIsSpecial": null + }, + { + "id": "-egso4hRYhx2q8JXxgDIv", + "type": "rectangle", + "x": 1139.5639491452682, + "y": 103.66339994974231, + "width": 167.45153115905373, + "height": 95.0465905248899, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "#ffc9c9", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "an", + "roundness": { + "type": 3 + }, + "seed": 1174123357, + "version": 812, + "versionNonce": 1708074643, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "jZuPfI77pN44VjlvBTQr8" + }, + { + "id": "arrow-dlq-alarm", + "type": "arrow" + }, + { + "id": "5wHYcPQUcNs3ZKkcJPLgL", + "type": "arrow" + }, + { + "id": "CVHj9v8VtWANiyBHn_Urk", + "type": "arrow" + } + ], + "updated": 1777090242283, + "link": null, + "locked": false + }, + { + "id": "jZuPfI77pN44VjlvBTQr8", + "type": "text", + "x": 1155.9297522614163, + "y": 121.18669521218726, + "width": 134.7199249267578, + "height": 60, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "anV", + "roundness": null, + "seed": 561141213, + "version": 756, + "versionNonce": 1630408061, + "isDeleted": false, + "boundElements": null, + "updated": 1777090123022, + "link": null, + "locked": false, + "text": "On Lambda error\n(two independent\npaths)", + "fontSize": 16, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "-egso4hRYhx2q8JXxgDIv", + "originalText": "On Lambda error (two independent paths)", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "1-mzzbWdMRAwwRU9upZjc", + "type": "rectangle", + "x": 1219.7906702073822, + "y": 339.7224791650915, + "width": 229.6361732567325, + "height": 70, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "#ffc9c9", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "au", + "roundness": { + "type": 3 + }, + "seed": 996090045, + "version": 1319, + "versionNonce": 1833885139, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "a1zbBBZcAg7O71nef8hXN" + }, + { + "id": "CVHj9v8VtWANiyBHn_Urk", + "type": "arrow" + } + ], + "updated": 1777090242284, + "link": null, + "locked": false + }, + { + "id": "a1zbBBZcAg7O71nef8hXN", + "type": "text", + "x": 1228.688857848932, + "y": 344.7224791650915, + "width": 211.8397979736328, + "height": 60, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "auV", + "roundness": null, + "seed": 902951741, + "version": 1188, + "versionNonce": 694679261, + "isDeleted": false, + "boundElements": null, + "updated": 1777090205529, + "link": null, + "locked": false, + "text": "SQS Dead Letter Queue\nCaptures failed invocations\n4-day retention", + "fontSize": 16, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "1-mzzbWdMRAwwRU9upZjc", + "originalText": "SQS Dead Letter Queue\nCaptures failed invocations\n4-day retention", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "qgzkIVtCI_ajbAcSZIc18", + "type": "line", + "x": 762.528234871007, + "y": -11.936061159278069, + "width": 1.139061588750792, + "height": 551.8120585503532, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "#ffec99", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aw", + "roundness": { + "type": 2 + }, + "seed": 1528161341, + "version": 74, + "versionNonce": 360731603, + "isDeleted": false, + "boundElements": null, + "updated": 1777090108412, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 1.139061588750792, + 551.8120585503532 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "CVHj9v8VtWANiyBHn_Urk", + "type": "arrow", + "x": 1223.189714724795, + "y": 203.7099904746322, + "width": 130.69131831753475, + "height": 131.51896678145312, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "#ffec99", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ax", + "roundness": null, + "seed": 1282873245, + "version": 89, + "versionNonce": 1221642355, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "cF04TXT3Nu2KUoYmnp7c0" + } + ], + "updated": 1777090248172, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + 65.50624434522962 + ], + [ + 130.69131831753475, + 65.50624434522962 + ], + [ + 130.69131831753475, + 131.51896678145312 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "-egso4hRYhx2q8JXxgDIv", + "fixedPoint": [ + 0.4994028122686735, + 1.0526057796748707 + ], + "focus": 0, + "gap": 0 + }, + "endBinding": { + "elementId": "1-mzzbWdMRAwwRU9upZjc", + "fixedPoint": [ + 0.5839252628767466, + -0.06419317012865966 + ], + "focus": 0, + "gap": 0 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": true, + "fixedSegments": null, + "startIsSpecial": null, + "endIsSpecial": null + }, + { + "id": "cF04TXT3Nu2KUoYmnp7c0", + "type": "text", + "x": 1256.143406110125, + "y": 239.21623481986182, + "width": 64.783935546875, + "height": 60, + "angle": 0, + "strokeColor": "#e03131", + "backgroundColor": "#ffec99", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ay", + "roundness": null, + "seed": 671469053, + "version": 4, + "versionNonce": 494167933, + "isDeleted": false, + "boundElements": null, + "updated": 1777090247805, + "link": null, + "locked": false, + "text": "Failed \nevent \npayload ", + "fontSize": 16, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "CVHj9v8VtWANiyBHn_Urk", + "originalText": "Failed \nevent \npayload ", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "YGFWGHs2y0sQCbwRQ16-F", + "type": "text", + "x": 218.93419755641747, + "y": -65.03040179334891, + "width": 275.51983642578125, + "height": 35, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffec99", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "az", + "roundness": null, + "seed": 1970542931, + "version": 83, + "versionNonce": 1543869523, + "isDeleted": false, + "boundElements": null, + "updated": 1777090376834, + "link": null, + "locked": false, + "text": "Trigger & Execution", + "fontSize": 28, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Trigger & Execution", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "gvqriNEpFUpTAVOVdKsGp", + "type": "text", + "x": 896.4125639346967, + "y": -63.140863082546076, + "width": 322.3358154296875, + "height": 35, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffec99", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b00", + "roundness": null, + "seed": 1385743827, + "version": 80, + "versionNonce": 2095863421, + "isDeleted": false, + "boundElements": null, + "updated": 1777090373591, + "link": null, + "locked": false, + "text": "Observability & Alerting", + "fontSize": 28, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Observability & Alerting", + "autoResize": true, + "lineHeight": 1.25 + } + ], + "appState": { + "gridSize": 20, + "gridStep": 5, + "gridModeEnabled": false, + "viewBackgroundColor": "#f8fafc" + }, + "files": {} +} \ No newline at end of file From b183e8cff6b4190cbcfef7e27c9c0f5f076fca7d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 25 Apr 2026 04:19:54 +0000 Subject: [PATCH 6/9] chore: auto-export excalidraw diagrams [skip ci] --- .../docs/architecture/01-scheduler/v1/scheduler-diagram.svg | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 diagrams/docs/architecture/01-scheduler/v1/scheduler-diagram.svg diff --git a/diagrams/docs/architecture/01-scheduler/v1/scheduler-diagram.svg b/diagrams/docs/architecture/01-scheduler/v1/scheduler-diagram.svg new file mode 100644 index 0000000..cade821 --- /dev/null +++ b/diagrams/docs/architecture/01-scheduler/v1/scheduler-diagram.svg @@ -0,0 +1,5 @@ + + +EventBridge SchedulerStop — 11 PM dailycron(0 4 * * ? *)EventBridge SchedulerStart — 7 AM Mon–Fricron(0 12 ? * MON-FRI *)Lambda FunctionPython / boto3stop_instances / start_instancesstop_db_instance /start_db_instanceIAM RoleLeast-privilegeScoped to specificinstance ARNsEC2 Instanceems-prod-appt2.microEC2 Instancetinyurl-prodt3.microRDS PostgreSQLtinyurl-proddb.t4g.microCloudWatch LogsFull executionhistory30-day retentionCloudWatch AlarmLambda errors > 05-minute windowSNS TopicAlert channelEmail / Slack webhookEmail AlertScheduler failure notificationLambda error metricOn any resultOn Lambda error(two independentpaths)SQS Dead Letter QueueCaptures failed invocations4-day retentionFailed event payload Trigger & ExecutionObservability & Alerting \ No newline at end of file From 1d2f4b20c39da0a9ce727e78e63c014a68411d47 Mon Sep 17 00:00:00 2001 From: Buffden Date: Fri, 24 Apr 2026 23:45:04 -0500 Subject: [PATCH 7/9] font change for better readability --- .../v1/scheduler-diagram.excalidraw | 534 +++++++++--------- 1 file changed, 267 insertions(+), 267 deletions(-) diff --git a/docs/architecture/01-scheduler/v1/scheduler-diagram.excalidraw b/docs/architecture/01-scheduler/v1/scheduler-diagram.excalidraw index 76630e7..0dd4cf5 100644 --- a/docs/architecture/01-scheduler/v1/scheduler-diagram.excalidraw +++ b/docs/architecture/01-scheduler/v1/scheduler-diagram.excalidraw @@ -6,8 +6,8 @@ { "id": "eb-stop", "type": "rectangle", - "x": 77.76972395042748, - "y": 33.34090049880999, + "x": 78.27576404499627, + "y": 33.34834226490656, "width": 240, "height": 80, "angle": 0, @@ -24,8 +24,8 @@ "groupIds": [], "frameId": null, "seed": 101, - "version": 302, - "versionNonce": 187535069, + "version": 305, + "versionNonce": 504500381, "isDeleted": false, "boundElements": [ { @@ -37,7 +37,7 @@ "type": "arrow" } ], - "updated": 1777090156747, + "updated": 1777092278916, "link": null, "locked": false, "index": "a0" @@ -45,9 +45,9 @@ { "id": "eb-stop-t", "type": "text", - "x": 122.19081312279076, - "y": 47.09090049880999, - "width": 151.15782165527344, + "x": 117.4257960884533, + "y": 47.09834226490656, + "width": 161.69993591308594, "height": 52.5, "angle": 0, "strokeColor": "#4c1d95", @@ -61,17 +61,17 @@ "groupIds": [], "frameId": null, "seed": 102, - "version": 303, - "versionNonce": 1040151315, + "version": 351, + "versionNonce": 1040956659, "isDeleted": false, "boundElements": [], "containerId": "eb-stop", - "updated": 1777090156748, + "updated": 1777092278916, "link": null, "locked": false, "text": "EventBridge Scheduler\nStop — 11 PM daily\ncron(0 4 * * ? *)", "fontSize": 14, - "fontFamily": 1, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "originalText": "EventBridge Scheduler\nStop — 11 PM daily\ncron(0 4 * * ? *)", @@ -82,8 +82,8 @@ { "id": "eb-start", "type": "rectangle", - "x": 333.39924038506246, - "y": 32.0351198327821, + "x": 333.90528047963124, + "y": 32.04256159887868, "width": 240, "height": 80, "angle": 0, @@ -100,8 +100,8 @@ "groupIds": [], "frameId": null, "seed": 103, - "version": 144, - "versionNonce": 976436125, + "version": 147, + "versionNonce": 1579152637, "isDeleted": false, "boundElements": [ { @@ -113,7 +113,7 @@ "type": "arrow" } ], - "updated": 1777090156748, + "updated": 1777092278916, "link": null, "locked": false, "index": "a2" @@ -121,9 +121,9 @@ { "id": "eb-start-t", "type": "text", - "x": 364.36630428887105, - "y": 45.7851198327821, - "width": 178.0658721923828, + "x": 361.505317100725, + "y": 45.79256159887868, + "width": 184.7999267578125, "height": 52.5, "angle": 0, "strokeColor": "#4c1d95", @@ -137,17 +137,17 @@ "groupIds": [], "frameId": null, "seed": 104, - "version": 145, - "versionNonce": 238422611, + "version": 193, + "versionNonce": 1196490685, "isDeleted": false, "boundElements": [], "containerId": "eb-start", - "updated": 1777090156748, + "updated": 1777092278916, "link": null, "locked": false, "text": "EventBridge Scheduler\nStart — 7 AM Mon–Fri\ncron(0 12 ? * MON-FRI *)", "fontSize": 14, - "fontFamily": 1, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "originalText": "EventBridge Scheduler\nStart — 7 AM Mon–Fri\ncron(0 12 ? * MON-FRI *)", @@ -158,8 +158,8 @@ { "id": "lambda", "type": "rectangle", - "x": 205.00710635565156, - "y": 179.77970297480005, + "x": 205.51314645022035, + "y": 179.78714474089662, "width": 240, "height": 100, "angle": 0, @@ -176,8 +176,8 @@ "groupIds": [], "frameId": null, "seed": 105, - "version": 29, - "versionNonce": 532985949, + "version": 32, + "versionNonce": 1068649821, "isDeleted": false, "boundElements": [ { @@ -209,7 +209,7 @@ "type": "arrow" } ], - "updated": 1777090156748, + "updated": 1777092278916, "link": null, "locked": false, "index": "a4" @@ -217,9 +217,9 @@ { "id": "lambda-t", "type": "text", - "x": 213.7467380084836, - "y": 189.15470297480005, - "width": 222.52073669433594, + "x": 211.11324410647035, + "y": 189.16214474089662, + "width": 228.7998046875, "height": 81.25, "angle": 0, "strokeColor": "#7c2d12", @@ -233,17 +233,17 @@ "groupIds": [], "frameId": null, "seed": 106, - "version": 12, - "versionNonce": 1217099187, + "version": 60, + "versionNonce": 1376626323, "isDeleted": false, "boundElements": [], "containerId": "lambda", - "updated": 1777090156751, + "updated": 1777092278917, "link": null, "locked": false, "text": "Lambda Function\nPython / boto3\nstop_instances / start_instances\nstop_db_instance /\nstart_db_instance", "fontSize": 13, - "fontFamily": 1, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "originalText": "Lambda Function\nPython / boto3\nstop_instances / start_instances\nstop_db_instance / start_db_instance", @@ -254,8 +254,8 @@ { "id": "iam", "type": "rectangle", - "x": 498.0789992507705, - "y": 171.71647894007057, + "x": 498.5850393453393, + "y": 171.72392070616715, "width": 240, "height": 100.23918180687508, "angle": 0, @@ -272,8 +272,8 @@ "groupIds": [], "frameId": null, "seed": 107, - "version": 126, - "versionNonce": 1884697341, + "version": 129, + "versionNonce": 35297725, "isDeleted": false, "boundElements": [ { @@ -285,7 +285,7 @@ "type": "arrow" } ], - "updated": 1777090156751, + "updated": 1777092278916, "link": null, "locked": false, "index": "a6" @@ -293,9 +293,9 @@ { "id": "iam-t", "type": "text", - "x": 560.2095763381728, - "y": 189.3360698435081, - "width": 115.73884582519531, + "x": 554.2350942769799, + "y": 189.3435116096047, + "width": 128.69989013671875, "height": 65, "angle": 0, "strokeColor": "#7f1d1d", @@ -309,17 +309,17 @@ "groupIds": [], "frameId": null, "seed": 108, - "version": 127, - "versionNonce": 1750721779, + "version": 175, + "versionNonce": 1542717469, "isDeleted": false, "boundElements": [], "containerId": "iam", - "updated": 1777090156752, + "updated": 1777092278917, "link": null, "locked": false, "text": "IAM Role\nLeast-privilege\nScoped to specific\ninstance ARNs", "fontSize": 13, - "fontFamily": 1, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "originalText": "IAM Role\nLeast-privilege\nScoped to specific\ninstance ARNs", @@ -330,8 +330,8 @@ { "id": "ec2-ems", "type": "rectangle", - "x": 95.6015954260049, - "y": 322.30010428837204, + "x": 96.1076355205737, + "y": 322.3075460544686, "width": 126.80416244779144, "height": 80, "angle": 0, @@ -348,8 +348,8 @@ "groupIds": [], "frameId": null, "seed": 109, - "version": 610, - "versionNonce": 1314478013, + "version": 613, + "versionNonce": 2121947677, "isDeleted": false, "boundElements": [ { @@ -361,7 +361,7 @@ "type": "arrow" } ], - "updated": 1777090156752, + "updated": 1777092278916, "link": null, "locked": false, "index": "a8" @@ -369,9 +369,9 @@ { "id": "ec2-ems-t", "type": "text", - "x": 114.589217421385, - "y": 337.92510428837204, - "width": 88.82891845703125, + "x": 116.60975336556317, + "y": 337.9325460544686, + "width": 85.7999267578125, "height": 48.75, "angle": 0, "strokeColor": "#14532d", @@ -385,17 +385,17 @@ "groupIds": [], "frameId": null, "seed": 110, - "version": 601, - "versionNonce": 1212515379, + "version": 649, + "versionNonce": 224484403, "isDeleted": false, "boundElements": [], "containerId": "ec2-ems", - "updated": 1777090156752, + "updated": 1777092278917, "link": null, "locked": false, "text": "EC2 Instance\nems-prod-app\nt2.micro", "fontSize": 13, - "fontFamily": 1, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "originalText": "EC2 Instance\nems-prod-app\nt2.micro", @@ -406,8 +406,8 @@ { "id": "ec2-tinyurl", "type": "rectangle", - "x": 268.14508011751025, - "y": 321.93606882590683, + "x": 268.65112021207904, + "y": 321.9435105920034, "width": 114.33911648841922, "height": 80, "angle": 0, @@ -424,8 +424,8 @@ "groupIds": [], "frameId": null, "seed": 111, - "version": 654, - "versionNonce": 1810517117, + "version": 657, + "versionNonce": 1841499773, "isDeleted": false, "boundElements": [ { @@ -437,7 +437,7 @@ "type": "arrow" } ], - "updated": 1777090156752, + "updated": 1777092278916, "link": null, "locked": false, "index": "aA" @@ -445,9 +445,9 @@ { "id": "ec2-tinyurl-t", "type": "text", - "x": 280.90017913320423, - "y": 337.56106882590683, - "width": 88.82891845703125, + "x": 282.9207150773824, + "y": 337.5685105920034, + "width": 85.7999267578125, "height": 48.75, "angle": 0, "strokeColor": "#14532d", @@ -461,17 +461,17 @@ "groupIds": [], "frameId": null, "seed": 112, - "version": 649, - "versionNonce": 113398643, + "version": 697, + "versionNonce": 2031613053, "isDeleted": false, "boundElements": [], "containerId": "ec2-tinyurl", - "updated": 1777090156753, + "updated": 1777092278917, "link": null, "locked": false, "text": "EC2 Instance\ntinyurl-prod\nt3.micro", "fontSize": 13, - "fontFamily": 1, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "originalText": "EC2 Instance\ntinyurl-prod\nt3.micro", @@ -482,8 +482,8 @@ { "id": "rds", "type": "rectangle", - "x": 432.8104644374662, - "y": 320.66159109468305, + "x": 433.31650453203497, + "y": 320.6690328607796, "width": 128.6567497576932, "height": 80, "angle": 0, @@ -500,8 +500,8 @@ "groupIds": [], "frameId": null, "seed": 113, - "version": 571, - "versionNonce": 2077561149, + "version": 574, + "versionNonce": 1857435357, "isDeleted": false, "boundElements": [ { @@ -513,7 +513,7 @@ "type": "arrow" } ], - "updated": 1777090156753, + "updated": 1777092278916, "link": null, "locked": false, "index": "aC" @@ -521,9 +521,9 @@ { "id": "rds-t", "type": "text", - "x": 443.3253932713909, - "y": 336.28659109468305, - "width": 107.62689208984375, + "x": 447.59492213549095, + "y": 336.2940328607796, + "width": 100.09991455078125, "height": 48.75, "angle": 0, "strokeColor": "#0c4a6e", @@ -537,17 +537,17 @@ "groupIds": [], "frameId": null, "seed": 114, - "version": 568, - "versionNonce": 893670067, + "version": 616, + "versionNonce": 1005411795, "isDeleted": false, "boundElements": [], "containerId": "rds", - "updated": 1777090156753, + "updated": 1777092278917, "link": null, "locked": false, "text": "RDS PostgreSQL\ntinyurl-prod\ndb.t4g.micro", "fontSize": 13, - "fontFamily": 1, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "originalText": "RDS PostgreSQL\ntinyurl-prod\ndb.t4g.micro", @@ -558,10 +558,10 @@ { "id": "cw-logs", "type": "rectangle", - "x": 786.9700048940803, - "y": 223.34318203526698, + "x": 787.476044988649, + "y": 223.35062380136355, "width": 134.87677588279962, - "height": 80.09384475974616, + "height": 81, "angle": 0, "strokeColor": "#2563eb", "backgroundColor": "#bfdbfe", @@ -576,8 +576,8 @@ "groupIds": [], "frameId": null, "seed": 115, - "version": 1078, - "versionNonce": 1004266579, + "version": 1082, + "versionNonce": 1273320253, "isDeleted": false, "boundElements": [ { @@ -589,7 +589,7 @@ "type": "arrow" } ], - "updated": 1777090092412, + "updated": 1777092278916, "link": null, "locked": false, "index": "aE" @@ -597,9 +597,9 @@ { "id": "cw-logs-t", "type": "text", - "x": 800.1594456919253, - "y": 230.89010441514006, - "width": 108.49789428710938, + "x": 797.7144817581739, + "y": 231.35062380136355, + "width": 114.39990234375, "height": 65, "angle": 0, "strokeColor": "#1e3a8a", @@ -613,17 +613,17 @@ "groupIds": [], "frameId": null, "seed": 116, - "version": 1069, - "versionNonce": 639754739, + "version": 1117, + "versionNonce": 1249795293, "isDeleted": false, "boundElements": [], "containerId": "cw-logs", - "updated": 1777090092412, + "updated": 1777092278917, "link": null, "locked": false, "text": "CloudWatch Logs\nFull execution\nhistory\n30-day retention", "fontSize": 13, - "fontFamily": 1, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "originalText": "CloudWatch Logs\nFull execution history\n30-day retention", @@ -634,8 +634,8 @@ { "id": "cw-alarm", "type": "rectangle", - "x": 951.0631712777617, - "y": 238.42462258218802, + "x": 951.5692113723305, + "y": 238.4320643482846, "width": 200.3190560721608, "height": 80, "angle": 0, @@ -652,8 +652,8 @@ "groupIds": [], "frameId": null, "seed": 119, - "version": 1427, - "versionNonce": 1035625277, + "version": 1430, + "versionNonce": 28435357, "isDeleted": false, "boundElements": [ { @@ -669,7 +669,7 @@ "type": "arrow" } ], - "updated": 1777090166962, + "updated": 1777092278916, "link": null, "locked": false, "index": "aI" @@ -677,9 +677,9 @@ { "id": "cw-alarm-t", "type": "text", - "x": 991.0977527196039, - "y": 254.04962258218802, - "width": 120.24989318847656, + "x": 990.9537912882937, + "y": 254.0570643482846, + "width": 121.54989624023438, "height": 48.75, "angle": 0, "strokeColor": "#064e3b", @@ -693,17 +693,17 @@ "groupIds": [], "frameId": null, "seed": 120, - "version": 1418, - "versionNonce": 375714717, + "version": 1466, + "versionNonce": 1757948787, "isDeleted": false, "boundElements": [], "containerId": "cw-alarm", - "updated": 1777090166962, + "updated": 1777092278917, "link": null, "locked": false, "text": "CloudWatch Alarm\nLambda errors > 0\n5-minute window", "fontSize": 13, - "fontFamily": 1, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "originalText": "CloudWatch Alarm\nLambda errors > 0\n5-minute window", @@ -714,8 +714,8 @@ { "id": "sns", "type": "rectangle", - "x": 952.429381211985, - "y": 363.9233979880932, + "x": 952.9354213065537, + "y": 363.9308397541898, "width": 199.12811251012567, "height": 80, "angle": 0, @@ -732,8 +732,8 @@ "groupIds": [], "frameId": null, "seed": 121, - "version": 1566, - "versionNonce": 311712957, + "version": 1569, + "versionNonce": 72181757, "isDeleted": false, "boundElements": [ { @@ -749,7 +749,7 @@ "type": "arrow" } ], - "updated": 1777090166963, + "updated": 1777092278916, "link": null, "locked": false, "index": "aK" @@ -757,9 +757,9 @@ { "id": "sns-t", "type": "text", - "x": 982.2095095495672, - "y": 379.5483979880932, - "width": 139.56785583496094, + "x": 977.4245416485306, + "y": 379.5558397541898, + "width": 150.14987182617188, "height": 48.75, "angle": 0, "strokeColor": "#831843", @@ -773,17 +773,17 @@ "groupIds": [], "frameId": null, "seed": 122, - "version": 1559, - "versionNonce": 12827933, + "version": 1607, + "versionNonce": 129546557, "isDeleted": false, "boundElements": [], "containerId": "sns", - "updated": 1777090166963, + "updated": 1777092278917, "link": null, "locked": false, "text": "SNS Topic\nAlert channel\nEmail / Slack webhook", "fontSize": 13, - "fontFamily": 1, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "originalText": "SNS Topic\nAlert channel\nEmail / Slack webhook", @@ -794,8 +794,8 @@ { "id": "email", "type": "rectangle", - "x": 947.0692079768228, - "y": 495.0473088804778, + "x": 947.5752480713916, + "y": 495.05475064657435, "width": 204.79791564112764, "height": 70, "angle": 0, @@ -812,8 +812,8 @@ "groupIds": [], "frameId": null, "seed": 123, - "version": 1511, - "versionNonce": 736466493, + "version": 1514, + "versionNonce": 1169776733, "isDeleted": false, "boundElements": [ { @@ -825,7 +825,7 @@ "type": "arrow" } ], - "updated": 1777090166963, + "updated": 1777092278916, "link": null, "locked": false, "index": "aM" @@ -833,10 +833,10 @@ { "id": "email-t", "type": "text", - "x": 957.2202943984607, - "y": 513.7973088804778, - "width": 184.49574279785156, - "height": 32.5, + "x": 989.1992577718382, + "y": 505.67975064657435, + "width": 121.54989624023438, + "height": 48.75, "angle": 0, "strokeColor": "#111827", "backgroundColor": "transparent", @@ -849,17 +849,17 @@ "groupIds": [], "frameId": null, "seed": 124, - "version": 1510, - "versionNonce": 514967197, + "version": 1558, + "versionNonce": 2016953619, "isDeleted": false, "boundElements": [], "containerId": "email", - "updated": 1777090166963, + "updated": 1777092278917, "link": null, "locked": false, - "text": "Email Alert\nScheduler failure notification", + "text": "Email Alert\nScheduler failure\nnotification", "fontSize": 13, - "fontFamily": 1, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "originalText": "Email Alert\nScheduler failure notification", @@ -870,8 +870,8 @@ { "id": "arrow-eb-stop-lambda", "type": "arrow", - "x": 223.4609186681424, - "y": 117.66681160825834, + "x": 223.9669587627112, + "y": 117.67425337435492, "width": 56.44333239715675, "height": 58.18662119296411, "angle": 0, @@ -886,11 +886,11 @@ "groupIds": [], "frameId": null, "seed": 201, - "version": 685, - "versionNonce": 1843766781, + "version": 693, + "versionNonce": 2033740051, "isDeleted": false, "boundElements": [], - "updated": 1777090156753, + "updated": 1777092278479, "link": null, "locked": false, "points": [ @@ -941,8 +941,8 @@ { "id": "arrow-eb-start-lambda", "type": "arrow", - "x": 436.5851044893495, - "y": 116.7147211194524, + "x": 437.09114458391826, + "y": 116.72216288554898, "width": 72.1531195842, "height": 59.025699977247854, "angle": 0, @@ -957,11 +957,11 @@ "groupIds": [], "frameId": null, "seed": 202, - "version": 403, - "versionNonce": 153977939, + "version": 411, + "versionNonce": 598517149, "isDeleted": false, "boundElements": [], - "updated": 1777090156753, + "updated": 1777092278479, "link": null, "locked": false, "points": [ @@ -1012,8 +1012,8 @@ { "id": "arrow-lambda-ec2ems", "type": "arrow", - "x": 259.4690417343513, - "y": 282.9290849507515, + "x": 259.9750818289201, + "y": 282.93652671684805, "width": 127.05558912727855, "height": 35.08433261696791, "angle": 0, @@ -1028,11 +1028,11 @@ "groupIds": [], "frameId": null, "seed": 203, - "version": 885, - "versionNonce": 228187741, + "version": 893, + "versionNonce": 923782835, "isDeleted": false, "boundElements": [], - "updated": 1777090156753, + "updated": 1777092278479, "link": null, "locked": false, "points": [ @@ -1095,8 +1095,8 @@ { "id": "arrow-lambda-ec2tinyurl", "type": "arrow", - "x": 324.90710635565154, - "y": 284.77970297480005, + "x": 325.4131464502203, + "y": 284.7871447408966, "width": 0.3075320060682998, "height": 32.156365851106784, "angle": 0, @@ -1111,11 +1111,11 @@ "groupIds": [], "frameId": null, "seed": 204, - "version": 1037, - "versionNonce": 406815219, + "version": 1045, + "versionNonce": 1570761213, "isDeleted": false, "boundElements": [], - "updated": 1777090156753, + "updated": 1777092278479, "link": null, "locked": false, "points": [ @@ -1158,8 +1158,8 @@ { "id": "arrow-lambda-rds", "type": "arrow", - "x": 389.0391566445468, - "y": 282.97477349263994, + "x": 389.54519673911557, + "y": 282.9822152587365, "width": 116.07282155163557, "height": 32.763756291454285, "angle": 0, @@ -1174,11 +1174,11 @@ "groupIds": [], "frameId": null, "seed": 205, - "version": 744, - "versionNonce": 786959037, + "version": 752, + "versionNonce": 1009352787, "isDeleted": false, "boundElements": [], - "updated": 1777090156753, + "updated": 1777092278479, "link": null, "locked": false, "points": [ @@ -1241,8 +1241,8 @@ { "id": "arrow-dlq-alarm", "type": "arrow", - "x": 1134.5639491452682, - "y": 151.08669521218727, + "x": 1135.069989239837, + "y": 151.09413697828384, "width": 150.87963997272823, "height": 83.39824799943906, "angle": 0, @@ -1257,8 +1257,8 @@ "groupIds": [], "frameId": null, "seed": 208, - "version": 3806, - "versionNonce": 1961390173, + "version": 3811, + "versionNonce": 2076658877, "isDeleted": false, "boundElements": [ { @@ -1266,7 +1266,7 @@ "id": "XohlLLkCprrVSNZlolUaN" } ], - "updated": 1777090166963, + "updated": 1777092278916, "link": null, "locked": false, "points": [ @@ -1344,9 +1344,9 @@ { "id": "XohlLLkCprrVSNZlolUaN", "type": "text", - "x": 658.1502765512571, - "y": 665.5734038418145, - "width": 107.05589294433594, + "x": 996.3501937061064, + "y": 184.40323777172642, + "width": 114.39984130859375, "height": 40, "angle": 0, "strokeColor": "#e03131", @@ -1361,16 +1361,16 @@ "index": "aVO", "roundness": null, "seed": 1418495507, - "version": 31, - "versionNonce": 2049525309, + "version": 78, + "versionNonce": 2049477021, "isDeleted": false, "boundElements": null, - "updated": 1777089626738, + "updated": 1777092278917, "link": null, "locked": false, "text": "Lambda error \nmetric", "fontSize": 16, - "fontFamily": 5, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "containerId": "arrow-dlq-alarm", @@ -1381,8 +1381,8 @@ { "id": "B3P9vgExjEeGVuApy8QZj", "type": "arrow", - "x": 1129.3854803168672, - "y": 321.55582969282483, + "x": 1129.891520411436, + "y": 321.5632714589214, "width": 142.7131893216697, "height": 38.64828087524643, "angle": 0, @@ -1397,11 +1397,11 @@ "groupIds": [], "frameId": null, "seed": 421514276, - "version": 4969, - "versionNonce": 244256797, + "version": 4977, + "versionNonce": 1608601277, "isDeleted": false, "boundElements": [], - "updated": 1777090167401, + "updated": 1777092278479, "link": null, "locked": false, "points": [ @@ -1464,8 +1464,8 @@ { "id": "arrow-sns-email", "type": "arrow", - "x": 1117.9807843399715, - "y": 446.6405255890901, + "x": 1118.4868244345403, + "y": 446.64796735518667, "width": 134.1567003240034, "height": 45.61549195771727, "angle": 0, @@ -1480,11 +1480,11 @@ "groupIds": [], "frameId": null, "seed": 210, - "version": 4736, - "versionNonce": 1171326077, + "version": 4744, + "versionNonce": 78497683, "isDeleted": false, "boundElements": [], - "updated": 1777090167402, + "updated": 1777092278479, "link": null, "locked": false, "points": [ @@ -1547,8 +1547,8 @@ { "id": "arrow-lambda-iam", "type": "arrow", - "x": 449.9560217085917, - "y": 247.77899948666914, + "x": 450.4620618031605, + "y": 247.7864412527657, "width": 43.22087344086026, "height": 51.02903359193152, "angle": 0, @@ -1563,11 +1563,11 @@ "groupIds": [], "frameId": null, "seed": 211, - "version": 222, - "versionNonce": 461425555, + "version": 230, + "versionNonce": 1000501021, "isDeleted": false, "boundElements": [], - "updated": 1777090156753, + "updated": 1777092278479, "link": null, "locked": false, "points": [ @@ -1618,8 +1618,8 @@ { "id": "h1m_RV498yMoqOf4Ff5O7", "type": "rectangle", - "x": 923.2398154270375, - "y": 27.82758507560237, + "x": 923.7458555216062, + "y": 27.835026841698948, "width": 194.39323724617003, "height": 65.50335463683223, "angle": 0, @@ -1637,8 +1637,8 @@ "type": 3 }, "seed": 2145051165, - "version": 632, - "versionNonce": 80809437, + "version": 635, + "versionNonce": 639151389, "isDeleted": false, "boundElements": [ { @@ -1654,16 +1654,16 @@ "type": "arrow" } ], - "updated": 1777090146029, + "updated": 1777092278916, "link": null, "locked": false }, { "id": "xc_N7Hc9mAD4It6adMwtU", "type": "text", - "x": 955.2064764695563, - "y": 48.079262394018485, - "width": 130.4599151611328, + "x": 949.4424741446912, + "y": 48.08670416011506, + "width": 143, "height": 25, "angle": 0, "strokeColor": "#1e1e1e", @@ -1678,16 +1678,16 @@ "index": "aj", "roundness": null, "seed": 346877373, - "version": 579, - "versionNonce": 646793789, + "version": 627, + "versionNonce": 28584627, "isDeleted": false, "boundElements": null, - "updated": 1777090146029, + "updated": 1777092278917, "link": null, "locked": false, "text": "On any result", "fontSize": 20, - "fontFamily": 5, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "containerId": "h1m_RV498yMoqOf4Ff5O7", @@ -1698,8 +1698,8 @@ { "id": "gISw8QyTtviZvSXZnXi_U", "type": "arrow", - "x": 918.2398154270375, - "y": 60.47926239401849, + "x": 918.7458555216062, + "y": 60.48670416011507, "width": 63.93142259155741, "height": 157.85805434376434, "angle": 0, @@ -1715,11 +1715,11 @@ "index": "ak", "roundness": null, "seed": 1970273939, - "version": 2307, - "versionNonce": 1889771261, + "version": 2315, + "versionNonce": 196689619, "isDeleted": false, "boundElements": null, - "updated": 1777090146029, + "updated": 1777092278479, "link": null, "locked": false, "points": [ @@ -1765,8 +1765,8 @@ { "id": "5wHYcPQUcNs3ZKkcJPLgL", "type": "arrow", - "x": 1122.6330526732074, - "y": 60.47926239401849, + "x": 1123.1390927677762, + "y": 60.48670416011507, "width": 100.55666205158764, "height": 38.18413755572382, "angle": 0, @@ -1782,11 +1782,11 @@ "index": "al", "roundness": null, "seed": 1987311635, - "version": 1868, - "versionNonce": 1380121245, + "version": 1873, + "versionNonce": 1411318141, "isDeleted": false, "boundElements": [], - "updated": 1777090146029, + "updated": 1777092278916, "link": null, "locked": false, "points": [ @@ -1832,8 +1832,8 @@ { "id": "-egso4hRYhx2q8JXxgDIv", "type": "rectangle", - "x": 1139.5639491452682, - "y": 103.66339994974231, + "x": 1140.069989239837, + "y": 103.67084171583889, "width": 167.45153115905373, "height": 95.0465905248899, "angle": 0, @@ -1851,8 +1851,8 @@ "type": 3 }, "seed": 1174123357, - "version": 812, - "versionNonce": 1708074643, + "version": 815, + "versionNonce": 723241437, "isDeleted": false, "boundElements": [ { @@ -1872,16 +1872,16 @@ "type": "arrow" } ], - "updated": 1777090242283, + "updated": 1777092278916, "link": null, "locked": false }, { "id": "jZuPfI77pN44VjlvBTQr8", "type": "text", - "x": 1155.9297522614163, - "y": 121.18669521218726, - "width": 134.7199249267578, + "x": 1153.395852475614, + "y": 121.19413697828384, + "width": 140.7998046875, "height": 60, "angle": 0, "strokeColor": "#e03131", @@ -1896,16 +1896,16 @@ "index": "anV", "roundness": null, "seed": 561141213, - "version": 756, - "versionNonce": 1630408061, + "version": 804, + "versionNonce": 1776442451, "isDeleted": false, "boundElements": null, - "updated": 1777090123022, + "updated": 1777092278917, "link": null, "locked": false, "text": "On Lambda error\n(two independent\npaths)", "fontSize": 16, - "fontFamily": 5, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "containerId": "-egso4hRYhx2q8JXxgDIv", @@ -1916,10 +1916,10 @@ { "id": "1-mzzbWdMRAwwRU9upZjc", "type": "rectangle", - "x": 1219.7906702073822, - "y": 339.7224791650915, + "x": 1220.296710301951, + "y": 339.7299209311881, "width": 229.6361732567325, - "height": 70, + "height": 90, "angle": 0, "strokeColor": "#e03131", "backgroundColor": "#ffc9c9", @@ -1935,8 +1935,8 @@ "type": 3 }, "seed": 996090045, - "version": 1319, - "versionNonce": 1833885139, + "version": 1324, + "versionNonce": 974042781, "isDeleted": false, "boundElements": [ { @@ -1948,17 +1948,17 @@ "type": "arrow" } ], - "updated": 1777090242284, + "updated": 1777092278916, "link": null, "locked": false }, { "id": "a1zbBBZcAg7O71nef8hXN", "type": "text", - "x": 1228.688857848932, - "y": 344.7224791650915, - "width": 211.8397979736328, - "height": 60, + "x": 1242.7149251041453, + "y": 344.7299209311881, + "width": 184.79974365234375, + "height": 80, "angle": 0, "strokeColor": "#e03131", "backgroundColor": "transparent", @@ -1972,16 +1972,16 @@ "index": "auV", "roundness": null, "seed": 902951741, - "version": 1188, - "versionNonce": 694679261, + "version": 1236, + "versionNonce": 1631487581, "isDeleted": false, "boundElements": null, - "updated": 1777090205529, + "updated": 1777092278917, "link": null, "locked": false, - "text": "SQS Dead Letter Queue\nCaptures failed invocations\n4-day retention", + "text": "SQS Dead Letter Queue\nCaptures failed\ninvocations\n4-day retention", "fontSize": 16, - "fontFamily": 5, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "containerId": "1-mzzbWdMRAwwRU9upZjc", @@ -1992,8 +1992,8 @@ { "id": "qgzkIVtCI_ajbAcSZIc18", "type": "line", - "x": 762.528234871007, - "y": -11.936061159278069, + "x": 763.0342749655758, + "y": -11.928619393181492, "width": 1.139061588750792, "height": 551.8120585503532, "angle": 0, @@ -2011,11 +2011,11 @@ "type": 2 }, "seed": 1528161341, - "version": 74, - "versionNonce": 360731603, + "version": 80, + "versionNonce": 406175059, "isDeleted": false, "boundElements": null, - "updated": 1777090108412, + "updated": 1777092278479, "link": null, "locked": false, "points": [ @@ -2037,8 +2037,8 @@ { "id": "CVHj9v8VtWANiyBHn_Urk", "type": "arrow", - "x": 1223.189714724795, - "y": 203.7099904746322, + "x": 1223.6957548193639, + "y": 203.71743224072878, "width": 130.69131831753475, "height": 131.51896678145312, "angle": 0, @@ -2054,8 +2054,8 @@ "index": "ax", "roundness": null, "seed": 1282873245, - "version": 89, - "versionNonce": 1221642355, + "version": 94, + "versionNonce": 1603787517, "isDeleted": false, "boundElements": [ { @@ -2063,7 +2063,7 @@ "id": "cF04TXT3Nu2KUoYmnp7c0" } ], - "updated": 1777090248172, + "updated": 1777092278916, "link": null, "locked": false, "points": [ @@ -2113,9 +2113,9 @@ { "id": "cF04TXT3Nu2KUoYmnp7c0", "type": "text", - "x": 1256.143406110125, - "y": 239.21623481986182, - "width": 64.783935546875, + "x": 1253.8414628062562, + "y": 239.2236765859584, + "width": 70.39990234375, "height": 60, "angle": 0, "strokeColor": "#e03131", @@ -2130,16 +2130,16 @@ "index": "ay", "roundness": null, "seed": 671469053, - "version": 4, - "versionNonce": 494167933, + "version": 51, + "versionNonce": 2008527549, "isDeleted": false, "boundElements": null, - "updated": 1777090247805, + "updated": 1777092278917, "link": null, "locked": false, "text": "Failed \nevent \npayload ", "fontSize": 16, - "fontFamily": 5, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "middle", "containerId": "CVHj9v8VtWANiyBHn_Urk", @@ -2150,9 +2150,9 @@ { "id": "YGFWGHs2y0sQCbwRQ16-F", "type": "text", - "x": 218.93419755641747, - "y": -65.03040179334891, - "width": 275.51983642578125, + "x": 219.44023765098626, + "y": -65.02296002725234, + "width": 292.5998840332031, "height": 35, "angle": 0, "strokeColor": "#1e1e1e", @@ -2167,16 +2167,16 @@ "index": "az", "roundness": null, "seed": 1970542931, - "version": 83, - "versionNonce": 1543869523, + "version": 131, + "versionNonce": 1189061523, "isDeleted": false, "boundElements": null, - "updated": 1777090376834, + "updated": 1777092278917, "link": null, "locked": false, "text": "Trigger & Execution", "fontSize": 28, - "fontFamily": 5, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "top", "containerId": null, @@ -2187,9 +2187,9 @@ { "id": "gvqriNEpFUpTAVOVdKsGp", "type": "text", - "x": 896.4125639346967, - "y": -63.140863082546076, - "width": 322.3358154296875, + "x": 896.9186040292655, + "y": -63.1334213164495, + "width": 369.599853515625, "height": 35, "angle": 0, "strokeColor": "#1e1e1e", @@ -2204,16 +2204,16 @@ "index": "b00", "roundness": null, "seed": 1385743827, - "version": 80, - "versionNonce": 2095863421, + "version": 128, + "versionNonce": 1393316637, "isDeleted": false, "boundElements": null, - "updated": 1777090373591, + "updated": 1777092278917, "link": null, "locked": false, "text": "Observability & Alerting", "fontSize": 28, - "fontFamily": 5, + "fontFamily": 8, "textAlign": "center", "verticalAlign": "top", "containerId": null, From aeca17f7008d00cc94abbb2117189de712eeb2ee Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 25 Apr 2026 04:48:12 +0000 Subject: [PATCH 8/9] chore: auto-export excalidraw diagrams [skip ci] --- .../docs/architecture/01-scheduler/v1/scheduler-diagram.svg | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/diagrams/docs/architecture/01-scheduler/v1/scheduler-diagram.svg b/diagrams/docs/architecture/01-scheduler/v1/scheduler-diagram.svg index cade821..fd89a06 100644 --- a/diagrams/docs/architecture/01-scheduler/v1/scheduler-diagram.svg +++ b/diagrams/docs/architecture/01-scheduler/v1/scheduler-diagram.svg @@ -1,5 +1,4 @@ EventBridge SchedulerStop — 11 PM dailycron(0 4 * * ? *)EventBridge SchedulerStart — 7 AM Mon–Fricron(0 12 ? * MON-FRI *)Lambda FunctionPython / boto3stop_instances / start_instancesstop_db_instance /start_db_instanceIAM RoleLeast-privilegeScoped to specificinstance ARNsEC2 Instanceems-prod-appt2.microEC2 Instancetinyurl-prodt3.microRDS PostgreSQLtinyurl-proddb.t4g.microCloudWatch LogsFull executionhistory30-day retentionCloudWatch AlarmLambda errors > 05-minute windowSNS TopicAlert channelEmail / Slack webhookEmail AlertScheduler failure notificationLambda error metricOn any resultOn Lambda error(two independentpaths)SQS Dead Letter QueueCaptures failed invocations4-day retentionFailed event payload Trigger & ExecutionObservability & Alerting \ No newline at end of file + @font-face { font-family: Comic Shanns; src: url(data:font/woff2;base64,d09GMgABAAAAACIEAAsAAAAAO3AAACG0AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmAAgSQRCAradMtPC34AATYCJAOBAAQgBZUYByAbjDKzERVsHIAQvC0RUUh59l8mcGMo1Ad2T+IaiTbSqWTWbFtJFcl2dg0cP2694UIQ5D8qjsExKPfj/+8eobFPcofnt9n77/3/if/5AS2giIKoiChWgIQoBljYM+Yi0rn1lbHs2+1qXuW223m73q7Su5W7dNVU1Xk9RPQESS3//P89a79ba2VR3PqiUWSBpQmkGNEMjozNGvsnAP7PtupXuFVpOz40siYO9IrxONHogqRJh3QFGBVsTJBxKbkg28s5ycWov6ohuwKQBN446ej+57JW1/bVHwp3yrKx9/yMnbEfMLC7SRaoQHAcEPr875f1sz27WQ5xcCE7EI7CKJSi3pz7pl/fvtsb+sfutyk3YXY2xdn9YQjRxSxRyJlZ4nxCDD4Fif3lkRiB17hfKAoJQnl4rFTQE7JMSFqzqUdxfDsWc+0EUZtXLLZ08HihW4/vmPM4RIIECeKb7V9fBEBjXr0IAL6nHgCBsy7sgc65eK8Ue/bBvy9+QU6G7TL/RZ7Gn5o0AAz8KP2ZDWJonIIpxPIi2L7F9X5jDfD1WzNLkC5TIZ8SNcLGmGiGhZu8R9+mLZLSBVz1ZWduN9msTfbr2fd+2c/7cT/sq53dl/t8n+7UPtjJnXjxAHORYKV1fUFqiRNs4Q6t0l9mUsdXQ/hgLs2rDnjPsDavzSldFm/MLU1d/OmWl0ec0n6aT0gYL+fiY3ne4w256JDDnsoVUgVK3hMnb20L2sdVG3TpytSkMnlJ9nR1nMKh9KVHZkhqUo3VZf75fq0iVVsRCnkTg/7UHDeoqsW/YlJKQzUrIj+xgonvcYTCGhezzQhbauuEVyuDAAPlCXPGjvqSOlE1YVnqEkAT5SN2ULYAkvkLBvX9bYRVTANvgBEez+VUlVUcP/ZA48Q5j7mkEB4/v79OuAugE9NEfkAzlNp6zliFcB9Ab5T6EeYI14Tw+yTnhhsqTmHqRthDeHV3Vo+M2VpNKbX0/PGdBdzUKeWRgp0dz9EQQtUbt7ooDOp+2OFDluJ8eOYIL7+2Mmg+LztHmMzZrPwVS18LcGm4IcMm5Ty+MhTC9ywIZ2RIY1qQAkxZpBri9XiHxsntEBM+OLLLf0+pLD1iBgbykjFFKwf3OrwQ7zaXHh9/It6++otsdn988Z5UeLYFYbbLfNEFNgSqZXSDxuAbdMJya5h2vIbaLMritBYCaYTumkbspMVk9+wqOloOhfAPN0yB35dK4YJun3AFgIoDXdDEib7LCPumCBmgYE1R9WdfW88O+wwGduiDF+q9JRzqzuuUXOgAoBlMlNYHyyJCMb9/+VnUWhBuYaLaUDrVCCpFIUwAxbS2Vo0RQk4urh5tEhYIOc7i9pePESYRHhpjKmvx1UFtVRfJ0x8AMNXS8oTZsDhNKR+HiCItZrM4q+DAvoiil1t8Yl2nZdLjkyQp2Y6dOUtfjU8XNLJPKsIB5JZzktW3MSIPWovsRlj0WljypEAqO5zHRAXkRiB1VffulZjuQGOrrU+O41kGTi7in/fvV6nAbZ/fNVFGC5S2mZ7IG+4k8ezV0wUP85yCDb8XPa3mS3hhsFenRPrwMc48fMQ5vzR+B3DsDRRMOPHjmL6G0v3tWsBbentz+ylj2OFLtbzd0czGzhsY5qg87nhssCDD5pJq1tWrfi1Oq9ugyoW2x8/FMi312KYHzzPdy6nzXoR6PLrTCoeKtkMe+aSBvC4xUtHVgsiuVeOwrsGEX/4BODK9UExWCg+1Kf1EC2bwBgCQo4TXS6e/ODX2ZvvipJy5dCq0L7ZLCPnfPCrrnJrSyQgrkPfRVwp5UlX9mA6qwGBlkrA4rHv28sJiYuXMzuLylBKOv67j3p2NXbEEd6WOzBIZqr1rfLnvkBGuDYNASXwus9s9oblD7wwwBcuq4ZIiWbek1dSzre6S90WKBYqMDLIQ750rG842AwUWQhLIvqnY2m1NsjSIALkfixX2fQ0eDX6f81UqsHvIdx+/tI4EpwGA/fNM+Ozu+GHJ+aoM3jkTGWuzqvPuHi/stXv15kRI7pqOMGmiRZ/InZ2fC14A8NnEWQMzw3Whcf2pi/oHwsSOG9rUOBWW9LYjeCQANFL7bNwbTidEp2uh4qSdM3epMwDaNoJeOwuaEQp/v3HsQ1Uf0gWycV8qrBTbOz7pG9Ut9HKlT0M5QW2vi7ZOEDc2LSklxWNobowR4WmjPHA0RelKGy97FfozuoxOLIKaRvc4d6csl1jye5y1NfDtCR3Cgy+5xzFRb+Y1AHpkg5UELQUbVwO5oEDhgOI/jI4NhQmHquXl8V7FBbtZRM0QyYhwtJjvUJn5jOMCvwkcpQBU4NrhWTiqKoqfEp2xtWxRcZMdVlV36XZQr0oO3eHxCBV0t1ZWmJ1MuD3OHzU+Prc5vcWBSZTUzU+HRmgkHK2qBlX3EP4mN0hxZra588jYrC5tSbhYoH4D6pQo31btBMI9zs+9yrxWWpddndWq69vzCJurPLa3Vp01gA9vVBK5yEgGlIcoxzAtTOQBdu82bBeTxKpSiG9JH7x9KJFi4mQ/Bloe620v3OPBsj+Z/meLSctJDfpz5uqi308ZLlQBbM9cNAFQbzZEJWOCaG+3kWw4yb4h3oH2iT9WcDgqweWDBQAr4shcJXxx9DYlBOIVUyWAH2V+z5yhBSJpLNyE1K7IKlOK9/icQNVMsS/QVpgkPF0bdqDwx2H5Spn+tAGcyxCMHDKdkq+PEMMk6oQHcyryqkcAJoLssl1XhI+MlT8IA/WOVp3w9nUdYItTv0/rUqegiGmiTMmep9vC5FnejIQqNa18dN1GAgrbiATZjCObML3tM84Ybgxwfmpu00Jl231xntnBTjjSHNmEYJg5yVlTJlbphYh06XGxAY0vHWHCN1dOAK6e7jKJ6YWDJbiNtQhPb09w6NVKRZfpdK80pJSacfauaXOmc+okxHXSs3lHE+UBp14W4vB8ypIpWX+XFQjb27lb4BpshKwpBDC/TwTGKayA3Gw4uf9OzqIpkncXPYFdW8+DCKCE5cmMJL5KZToAs6kzK0NvzZnsTuZkqTWrLd3iGFLc8rgsHI3gD3WjO1huC/FgpTzgFBQ7PIOBgjDZX6+VHGnSWrXTkNlO0Po6h9mjil7yboQUkPJh8TM4OchAkp1ck2yiH6E/7X1uPY5vdmZaE2qOc2NYltYxAHTsBLOfE2hFVOLSR6Ol3mOxX1MnBLOTZ4cFvTI69syC/blbNfrJQThYMI5a7ljuKTHmgZv5DUzlaC3otTFsd1Mx7PyQcpv0p6XF/qt70LWQshBgFtvpgvaApe/mrrDv51U/eReHh84GTmjWq/e7FUJPH2E7JhrjbcDqwN6Lr9Kkz+zZ9AYix3XtEJK8/CHUAK8mjkOGandLq/gX4NrAjcJPcM8ess176xe/ma3vo+Pb1nrVY2eYaAQAjs7eVx0z+iSR1o51wo/S1Ql8JgwHy2CTOIyVSThHtVqiMdpEC8Iqn69qw9x8EuoNFceWhr99lXxt/fw+Y9qmJhB37kykbZpm4wrRjbzxUBoAyMB08KTZtU0flFiL7kyh275ay+uHJwiD5Ro/91RFiATb1ATtdQ2o+MVmDVpYMQWALLtG5V22qVsAKfBwHB+cEUL8UUP0PT8NZlVsyKzWl0TlCE/+2QvBuQgeyIBIj3j3srTaujPuyowi6VKuApFY7X1wcBhPVYs6IxgJKleCBVIVu2Lf0k68Tqv1lHqiZXoDbb1sOC0uOru7FYOMq7NdDYt2wpKzOh1lKwnageHpQC1eZA6vsoOE+hGVybtqNz8VQjh8T/C6UlbXucQzMMmjjsc2iTG/Npwpl6WhAhPmljp0rTZ/+IofMuVn6dRBWahU9HNxeHLwcNKU3liXZtnRUWY2GPuv/j8S/uzITdoWp33J7YTWGquPJx19v0KW/hFdoXWT6vwyKj+TgRoAJtwMIHuUqgf3ns8yWyQqpdb2Ze76x91P7/cDuHj3/1z379nw5w/+8B235LwXtPg0lCwsjtLNedSmkf2tWJeodfb1G+MmZL1TUucKu95QFwvPu0jxKxfdBMH1T20Mffvdkn0KAk+Ms2uOXG0S2ExnI+IMZWtS0p0Juumv5y6a/vOUBw7vtvVxYbBiUXLQkd9s6SHLrE3CTr7zwrtLnb9HU89plE+xmscfLp5eLyxGgRJNSeRES/lDJReM4AbAkUX0ABcR5JQPLeWRE0s0JSggLK6fvvjh4zr7lFLzHBX9u3Ppuxf4TmFnk5Uss/TkNwcd4PFjk8hq/iWZZrqU4ZQQDTpx3qY8sZfHUezQKlrQVj1m6O97321+2hEk6dVDHUqS2XVSFW06JW8nmW2/0+ys5VLc7gAUreqt0Ux5ikXIcHijlCD6xo3d8lD6ace8lKHDM8xCChxxeOZAjfoCzV7W0MazXyk1IyxzGShoJ6GXF+cIj0PMEJOWswBcmc+XLq/eULbC+OqmlY2Nlye+Ip8zlEMSin2XHHUFk3wLxQml7pWy1zwzBfTGWy4FKQG4sg5smDQWwkhKJDIpoui2C5On5AVMbk2RsSLNQCuTlDQZnHAxrqjdK976LykmCmpnvJjScEujT9v+Xz1e5IOeKW/aveYkJenE61IJwpqe0jXvebfnrRdAS0WU2RnUsRiuY1gbmozPjwhtqA8Rz0ax3Pe023FapeihZKgetcFa1hrLQ7WeEY4WYxLdhp0ss3hXlKQVzAIzQKRSLWWWPAGqsrs9keeMnZOaW5P3GCuScv/I6DB9bTefdOH72vhuuxnhEudYmW086oT1J11sYqTMNWa8dJkvcc0/htRnUi3O5FvCMxCTkBcrcYIB19/8NHfWZOO5SE/3cobAUy5+SOPOc+cEj3qZ/sLUnApPl+w9mTReUfbbuzkQwvivrmVaum7eOGvH6W8vpuAEsxwL5nonN5fVYhDBqM1vOK/N8bMVxaBPwWsldATDOryF0WdXu9sIevZHP7EIMblzM6v9nZWT/znxhwRC5jsyPZsIwVZsInZMxKb3SJIRHRNitdYIkXTKoUr/z5O3RnteSgd89LAb9gFPcAVD4JUXSQkGzwhv1Vt9VdNaMlL8mTkTuraZZgqpV7JoV4gMqhfbJkqZyBowBusCNllXpQRHZns33zb4zX6T7WtOzyVjC8Nx+QnOyFeV/vjHV22bUNdaCDr76rqPZ++dEUZikX/iBo7pvlrQEVzTPpg640jiaQlhj+mJE1Gl6ZPbj1SsyBrzSndzELt2LkSwS/cx7AVwbSoVERkhb6uoL60tmh/BiOdap2UIRA17bqjKssvySrNvPfXCX+otLsC/2l0vIs1TVCspRnG5wd/ZOL4V5F03fb6eFazYPDNLQiW91zR1V8Iu4s+sLVu82+JEF67oHtk3L/8P+M2OmoxkBHxON7EOoWhA9V6HehLj46Srhl5uMbSFdgsGRMKOi0GLmC606Sqq5zwpoJ82uZInJLUmBjUnQon4s/ThpfRlxpfiXokd6FsmEcX1H08afDPSG1l5yVRHDH8ZsRL8RF+7Nkwz+xD/6TNyhGAcShI54DwNKRYLeQkhk4lf5/FxNw1nxKSdJcZ8c705fdOm3vF3Q7MV0ZzUmz3e4qjmY78TxpEOhXK023D8SD4nM3y64V5khkM5KkbTxWdi7ceLNfIjnLIqE4zbzqMP8kPHIKK+Ezrm6Kzy08MQSUbiFQJEHf5aaqrK8XQmrS6NymP+1RY2Jfbc/fHHezIu/YunnlmXYSPIlPK4Vm2lZULeC81LZnpAjo4kW5a+Jzb8CfEE3E5lwOWYE9PKWZmEvo/KJzVbmua/ss2irUv3ldtG2jGnWBsxo0bi0L58gyuKCufPaQxMsr5PLQRDBEHyJ/q6CJdTpgvZX8uPrQRj5+sJnYJFQPw6vzdzwqFOvLUSVc36k2anTpYj1H+mzRrcW0l8jcOWvKQOPIz7EAf2D42tJMaQY4go1h+ZbBmo60SN5J+DIuWkvTT7wi4lAhuUcvFdHoNHJ6IEZBcvX6IjKZGQZ/CQ/6HsLZ5wcgw61pZgmHFy5jma3bVEhUHeYYiugaUEEcnGyRTuYyJRDN/nExhn/0GzS5vkCBlLiH2aCF66V0ZiFZhPD2ryj9vtTgHyg/A4FBEpZ+TYDP8MCJXb3maZCd1lWLFa3QyCgplKmu1dKsWdxhJ8UCCQKhIJRu+IRMXpjirg0VuZ1sQTzgMTZsJJSK/pYBk/OCusWyCch7dg0f8gE7jHiNlsNagALk78Og8x/seftDbyaTgWc4knZSd24o3CYtG5IMEuQda3yMM2/8hBxG16LTEsn6fsV+8ROqcJe4kw8rVkyAFBAN0eDsPs3+tk1ITyFNEC8WS6aurGTDMDoeRebY9sFb+J62+LEy8liwN0raTkjYJaXywLoeT1ghxqP/0qvctbSIvjQhfR8/wFu6vFi4S7yecw3wLFKrw4k55E170NLokMeDWQO/x09tPuOaGByt0qF3JtgWvkSIFIEkdQt/UvkzM6DXoKHqkSU0VmhIw5GhnulPzdtc+5qqK/4rF1Eh/mQz60MA/H+R3vSbWns4UgbG1LAxPIN8B15TF/nMPz60/JOMojD+rKJs+tCJg8urrYUJpBiOKRkCyZcNHmGypjrBX2BkeScgJeKSGJ+IyApzo1rajsv8HYKIOCwCj33BkA+84yNwa6Cshqgfz2HSkGwU9vyBBCNdhkuJSm9IzYwEij60XC4r6TMa8NnBUkhzT7okvZNENTnrvabJ3Le/CrEqxYlqNWf7POWOAxkdM0xs/X3wW0Mj1oyfDom3kgteXgQV3Z5DlVgdJZ46jZBqFQw3MiIuA/bPde/Sen5HqxSBi3cvMainTJv3wvv/HqiUG6QtyPlc3lCSL14zcvzFvXM2J9ZhrZINQbaSo5QLqKylPT3KX/DWaINPqIOLlH+hk4Sh5/vNzdWqRA3hphpVQuGvGl9cc3v/R4jEgSLRMwFKXVEVEaCS2olxKCtto6lVh4rroTfyI57LYEzQm+IkMLP1tTl+fO+25jJps5bfNmGieuxf2iJP3RM84QBD3chc/W24xbqhNatCYVBfJXMARyqs3vxZ6w7uu0WIPy001Veg8pC2ToFXHGEnfmWGOROKXT1GP+JdIcTRKS/rTTyVFf/D2kiflqfxEMm+NkRYZMaziQ12HI8HZkgPB2Yws+HZuFWdRqmt3zhAqDhjJ4xg770DY0gKH9nYFIVSTmwfdiQU0iz54NIOPKdp7ZtYMnwF8r6PBO7GI/1UJNHRdkWsYLSyTPkRMzZEoGIwkcoeJns3jI7qfW0QuZ1mWrF7mcDKSTlUQJUWQpZLfzO/k1k2trTbt/6/JsLTVdvEw8UxAGAlJR3n6xQyjeaNFhkMerBJPFy1uyhOWpXfJXlIPyJ0FIMjx/LKgA9osS9rJG0QpmzgLxmhFWsqRJhYFLW5YUmmJFQoqufz1CyK39lIOQ/e7WssiWqHEluRndRaYf1B5Ds3WR39+mH+czGe8o+0topXpbxt65Mai+PtkWJXN8EVUObhNCVPAI7tylRrPNp+5RP3kGYsz3l6MLQL21MQk0YHupqNmjEONGRiKVoCg/0OdVpQyXGLUfv5b0Qy9Esb8+crxgDVY70+RJNVQa9iy+9xf4bnYBxdS/cHOACNtjd22wWWRXn/dWJAiELFAHvgyRpO25/1uPx7QLqIGby2IFzMA0acAvSCSI4WLjrVcGYhACwcQF/vIWc6qjvBQ8iDTO+LONVOw5lZz4T7a5LDq3iGcLcISQ9dQPgUD0sM2v7AalcKEm5gI3+mafDieE+HTYDZfFiwSeee4RnX75m4VLlWqBkAMcw9nUgjgMDtL6/EoJkwfBb5kDQ6814XgzcBSlOKc706ILisLGVEXq6LIN1sdup41tKzYE9MWqBZP+SUFI7RsnrZI2S3HEPP1jEBHsZ5WyfeHdif3veVVuvaHpEVjiG40cpmhtFMdKC5Fffpyqst+cJklMKbITQsWpY1QOWZ85i63prChkRKK2BqCcvf6XSFuQXU32Yi4oI2f8IdV4Ga4xgnWBikowuHfXY4xs5wY1BCc+Gkr2Axl4aT9jxMZORzPyG5PrvVlhnS16/3e3dea1f57YrvXPaBD5dDyR64vJbQahxbNAsbWruKBVl+o4op1IJsQG5auKZDjexh/8KV7CKmRGd4FND6HBIouIIZrBi19jQigGvhTyPLMI+WCNWs3Twgisqws0Aa35r5BgBHWgKSY6nFdheK5X7IyR0AVplZlR//7LY9joXZVDheLlCkbn0RnOSraA/WjR9+me1JJ3qjr+ARgljvUpSJK5c1mKweG/flAilI89fxy87NBckPGvaPSgARuHTQU2b97gqXVGHmCj27IGxfZy34iksCa/8oEAvLb5dQlCV34n/EaGi7EN8HEYNJiUux5neLMiGRs+RhDUKLlGGQoTBtQFZ4Kxh//2X601nOCGV0RJ8qE2RyYDAQqT3Ocg99l6pUBA+Sj0RrLsw7WcOy9Lr6yGTmgxQEafpEEoZuubLAaZEbFKGCOVUQKRKImziDFMW97yERdlibXEKCCO614/zWCQnRXN8FEOnzuQx6vtrhuMVCSS0FYUBC8eJVlBUmVqfpGzHQthAcolqbbojn7GYZD7m4rKkcxIRmUNxihl++kVAiGtkVjF5ZrIOyM8BodXidlFkFRnuMlSitHd5SDG//SMkgAP1cMl8amez05bcZSla8vy1Vgy48v02UXX37rIsOTUirzZkK9AKGP3ICyhxOHvErOzssajWpJwNU0HoXPT/js7XJ9H2JHSpTQmelU67UQQRCjm1Tfs7uLEYQmtD/3hAx6hRKv6+FNu9Ctajw5gr9RtsJWF+sQggAVAMFMHQZTzTN8qZ04ESfDsAZ0s2m9YDd57Ui/pPfXwyO9Wgtj/51Q1huR5qWM+sOP00z9HRTM4ghj3rMUdY3uUh0GSpGmrKERBTHNpiIVwtFvD9kBCmeURBCiGlPGfvKkTg+L8QlpsDl48SIt6ao8+s84iqxBxRimnzjlTzgVC9Rb//vAR0W9baggcSXSFplkCavXdnMCaiZqRKua+lHp904/kyTcqlL0XT6pJwp/k9CY2qVIdLUngmOATWb+aJD1YVw0WFKkTpVmpNs1lhh3RKCVncBUljsmkaZ6br+N1AkEc2zsRyTSXWfqCWjkOHIfIqxMIBYxQpThO4IrODz77dnoKwpmjX4C1uojL/peTRb0r3iKSCDNWYrLF0SqxUH2Qk55XqyxUtERiwoq9nmsR1rr4DxmPwISFtYrVo/wNpRF4KBhyr9IfGoUYf+cOKCSzw90T/K6FNe9EBtsZqrjv4myxaH/4oLbRvVvnstZ596gCfZkDIlHH0Mwsignt1rkTGnMXgfeFY8lvOQS5z2Yf52rosLC6kvdqn9U3Vu6m6Pe6DJOSzpAtOMGvf+sKQptuZ2fTrZImSe2YLmkXP1ZaP6H2hdHjT3QRdAU/WTnv2TY6TLVQrRmJNw9hwv7VzgUykvRz02RTVV1gJ/57oLYy7oNlxESSwwD4dFshxJlTe8KfX01oL/VOvcHJ//7YUnf0uibhbGFedW0MtOP0liNBnJC8O1gUeg3wWypKD1iY9c+lQEwOwOPmpn2eZXeXx7WT9Bsfj1EIqCmP8ua9mjW58UNtSQdDmVdcXEWJemoPqoOBIwZ3Ql3JHn3ZCfOAdPbQ/kxaAiY6+4w8weTTEdo/OGqvQUnRMoWEVcsGZ+6N4jjWuj8aJ8qKGAYrR41z1d8xktsqrgmbAiZies1fDHsJrMxOOpboB73875JpHlBVDfSzwBoQyhxe2AUqlf38bWDW7JqcufrIBbgTEECjvBe5+U79f8Z+TAAP62uVo3P3elptx9y5eJMHwKtu57CDK9PpR1e1WcXckHsdl9+Im+2R1m0Pek5O/xntgNIuu9FB6f3lfk/L7X932i7vM+/sVYfFJNynpav+7DnJ0N3kbJrJG20rc8aEEL7KdEvTcNdJ/7rTxpP+drvdL/yaB22T0BV320TXzRg4wNrV/Si5y1a0R9JMdGm267NmB+FejuhhO7HShTB4iKVrAZzQdiPxbTy+A+7XZc7ZT266xP+q4W5fcveni+tfOdasflbeLhg1orxRP89nSvb/uFN/VdJfLgR2WRNX2q48pm5rNfGQeKYB//BE7//u5yCriy6tv/j3v4wMArUe/xoWZ3fBz9PDp1Xo/15apfI9P9D2Wwz2DVv8gK77kXX/LhH2G1f/u+IzTS5jp1aueJchwG4wN1XP/cT9+5nN+xNSaOTz0C8i/3OvdsZR8ujn3+jgsRcAQvAIDv1vtk5Y77Ssx0WYm48eruuXOmYAGPXpEa/baWCWL02OUuly5UnTwsDEzHS4OIGOVbIkZoeKLLRzlZ383HJ4lSuJkUs5KivyyGKuvUXZfNWElo3V4SYCzfICGxF2w5nrsGnACQC4/1QCjRDsKAJA9HL6/TSMxd7TIEb/aUgHeyk+P40gZmby8NkAcCbs9dxkbp1cLnjsFFV3Sh7zyXIyE64o5IIfh6SAxfC+cADUpeH4vEAbJ+bbcUnNUosbWKwsBwYFzexl0WxSzJMCIfc5b59HUzHJ3Au2D3HXn++wyBaBHm7uK/GmF0tWUJF0VCL6Lzjf5FR82ekI8iO+0gSTEMW4cJIlFy26dEmi9huaWrHg2EvDKAmKHzNXzctr1U8O8ERF4XGt5aOWLZRHPYzPQaNOmj2px1GRBgYCM5qjqnQ+knICJF9fArtB0inMhCiAHV65gQIMt9dUiU5lL5UJfp0mQLgU0SSCvwmpFJEaKvmz4AvOuoKEDarxzXbnLgkZutm4ZMgAUnp4oG6Icnf7qH4KKo8aIYi2AzybHiXwaib22tWBAVWGbhsGQAGJslNPkCvYwmlPTTmGvzjY1E5tIkq0mPQblfSeOiOgo/xcWhTFtwlJYyyuv8HmEkvKoU3NeMNy2jGqQqbtFhjISZSODxrVptKttRmEEU6d0dk3a1AHnstL1BU/14F9RjV3Wi5HMJkI6go1bGO+dFt0kH0X7JTIhSXQFIaEYO5o6rH4sHwFniNK0ijP98vLllqsueAryZpd3P7Lvy2nxQ5KJAmXhfRbUbuQlfaA3pdiOh7Jaa2lIo5gRDhmJtt+FhlMsluJn0SmoJKQdr6xzBFYIW0GzGXhlkKmWc+EqsKGMsKa/lZC+9kpbGgbA1ZgF0esBmtwPstHeMu7QDZfjDzWDdZuAW+B2bLaFh7vIq4tdZQ1zGdYaUuVo2TPCiDdpkQih7lUrKuLHFaaJDQjo8CeHiG8dxiMIhwjD/QAClzC+tonDFI+Wz09Lp884EjF4Gch6hzChyM0mOQkC6kJgiHqAVufpiViRIGvXRwmfZRmTYnRikRyYi5agdrUw/C6kJQ1NIlMScImsbJ+KdyfLaFZ3T08EgcqMyCjTXcDM9dgsgX0o7DSoMMtAuRIGziTYFSj42wVKGEL63hIxyfTDsgVkzxAzXTxHSZFLgq1FnGYRl9RWD5oz8zEZ9iCTkA4StNMgRtqCtwcetcn/zcAAAA=); }EventBridge SchedulerStop — 11 PM dailycron(0 4 * * ? *)EventBridge SchedulerStart — 7 AM Mon–Fricron(0 12 ? * MON-FRI *)Lambda FunctionPython / boto3stop_instances / start_instancesstop_db_instance /start_db_instanceIAM RoleLeast-privilegeScoped to specificinstance ARNsEC2 Instanceems-prod-appt2.microEC2 Instancetinyurl-prodt3.microRDS PostgreSQLtinyurl-proddb.t4g.microCloudWatch LogsFull executionhistory30-day retentionCloudWatch AlarmLambda errors > 05-minute windowSNS TopicAlert channelEmail / Slack webhookEmail AlertScheduler failurenotificationLambda error metricOn any resultOn Lambda error(two independentpaths)SQS Dead Letter QueueCaptures failedinvocations4-day retentionFailed event payload Trigger & ExecutionObservability & Alerting \ No newline at end of file From f84df38ad6c348cd08cd4a7422d64b5db5657643 Mon Sep 17 00:00:00 2001 From: Buffden Date: Tue, 26 May 2026 18:29:37 -0500 Subject: [PATCH 9/9] update workflow --- .github/workflows/export-excalidraw.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/export-excalidraw.yml b/.github/workflows/export-excalidraw.yml index 599a69d..f1b6502 100644 --- a/.github/workflows/export-excalidraw.yml +++ b/.github/workflows/export-excalidraw.yml @@ -75,5 +75,6 @@ jobs: echo "No diagram changes to commit." else git commit -m "chore: auto-export excalidraw diagrams [skip ci]" + git pull --rebase origin main git push fi