diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251019160137674.png b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/1.png similarity index 100% rename from docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251019160137674.png rename to docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/1.png diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020174712659.png b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/10.png similarity index 100% rename from docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020174712659.png rename to docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/10.png diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020180232079.png b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/11.png similarity index 100% rename from docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020180232079.png rename to docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/11.png diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020175737615.png b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/11_1.png similarity index 100% rename from docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020175737615.png rename to docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/11_1.png diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251019160303146.png b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/2.png similarity index 100% rename from docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251019160303146.png rename to docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/2.png diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251019160355415.png b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/3.png similarity index 100% rename from docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251019160355415.png rename to docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/3.png diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251019160413738.png b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/4.png similarity index 100% rename from docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251019160413738.png rename to docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/4.png diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251019160500983.png b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/5.png similarity index 100% rename from docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251019160500983.png rename to docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/5.png diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/6.png b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/6.png new file mode 100644 index 0000000000..6dbc4a1b31 Binary files /dev/null and b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/6.png differ diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020174203295.png b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/7.png similarity index 100% rename from docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020174203295.png rename to docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/7.png diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020174103427.png b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/8.png similarity index 100% rename from docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020174103427.png rename to docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/8.png diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020174425706.png b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/9.png similarity index 100% rename from docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020174425706.png rename to docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/9.png diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/Post.md b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/Post.md index e6476d6ad0..436d82c3b4 100644 --- a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/Post.md +++ b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/Post.md @@ -20,7 +20,7 @@ I see way too many .NET apps go to prod like it’s still “F5 on my laptop.” ## 1) Publish Command and CSPROJ Settings -![image-20251019160137674](D:\github\volosoft\abp\docs\en\Community-Articles\2025-10-17-Optimize-Your-App-For-Production\image-20251019160137674.png) +![Publish Command and CSPROJ Setting](1.png) Never go to production with debug build! See the below command which publishes properly a .NET app for production. @@ -51,7 +51,7 @@ dotnet publish -c Release -o out -p:PublishTrimmed=true -p:PublishSingleFile=tru ## 2) Kestrel Hosting -![image-20251019160303146](D:\github\volosoft\abp\docs\en\Community-Articles\2025-10-17-Optimize-Your-App-For-Production\image-20251019160303146.png) +![Kestrel Hosting](2.png) By default, ASP.NET Core app listen only `localhost`, it means it accepts requests only from inside the machine. When you deploy to Docker or Kubernetes, the container’s internal network needs to expose the app to the outside world. To do this you can set it via environment variable as below: @@ -103,7 +103,7 @@ app.Run(); -![image-20251019160355415](D:\github\volosoft\abp\docs\en\Community-Articles\2025-10-17-Optimize-Your-App-For-Production\image-20251019160355415.png) +![Garbage Collection and ThreadPool](3.png) ### GC Memory Cleanup Mode @@ -140,7 +140,7 @@ ThreadPool.SetMinThreads(200, 200); ## 4) HTTP Performance -![image-20251019160413738](D:\github\volosoft\abp\docs\en\Community-Articles\2025-10-17-Optimize-Your-App-For-Production\image-20251019160413738.png) +![HTTP Performance](4.png) ### HTTP Response Compression @@ -194,9 +194,9 @@ var json = JsonSerializer.Serialize(dto, MyJsonContext.Default.MyDto) ------ -## 5) Data Layer (Probably Where Most Apps Slow Down) +## 5) Data Layer (Mostly Where Most Apps Slow Down!) -![image-20251019160500983](D:\github\volosoft\abp\docs\en\Community-Articles\2025-10-17-Optimize-Your-App-For-Production\image-20251019160500983.png) +![Data Layer](5.png) ### Reuse `DbContext` via Factory (Pooling) @@ -251,7 +251,7 @@ Use EF Core logging, SQL Server Profiler, or `EXPLAIN` (Postgres/MySQL) to find ### Migrations -In production run migrations manually, never do it on app startup.That way you can review schema changes, back up data and avoid breaking the live DB. +In production run migrations manually, never do it on app startup. That way you can review schema changes, back up data and avoid breaking the live DB. @@ -261,5 +261,5 @@ In production run migrations manually, never do it on app startup.That way you c Use [Polly](https://www.pollydocs.org/) for retries, timeouts and circuit breakers for your DB or HTTP calls. Handles short outages gracefully -To keep the article short and for the better readability I splitted it into 2 parts -> [Continue with the second part here](Post2.md)... +To keep the article short and **for the better readability I spitted it into 2 parts 👉 [Continue with the second part here](Post2.md)... diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/Post2.md b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/Post2.md index 36007bf9a8..608ccfc2e6 100644 --- a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/Post2.md +++ b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/Post2.md @@ -1,6 +1,6 @@ ## 6) Telemetry (Logs, Metrics, Traces) -![image-20251020173353352](D:\github\volosoft\abp\docs\en\Community-Articles\2025-10-17-Optimize-Your-App-For-Production\image-20251020173353352.jpg) +![Telemetry](6.png) The below code adds `OpenTelemetry` to collect app logs, metrics, and traces in .NET. @@ -31,9 +31,9 @@ When your app is on-air, you should know about the below tools. You know in airp ------ -## 7) Build and Run Your .NET App in Docker the Right Way +## 7) Build & Run .NET App in Docker the Right Way -![image-20251020174203295](D:\github\volosoft\abp\docs\en\Community-Articles\2025-10-17-Optimize-Your-App-For-Production\image-20251020174203295.png) +![Docker](7.png) A multi-stage build is a Docker technique where you use one image for building your app and another smaller image for running it. Why we do multi-stage build, because the .NET SDK image is big but has all the build tools. The .NET Runtime image is small and optimized for production. You copy only the published output from the build stage into the runtime stage. @@ -98,9 +98,9 @@ I'll explain what these Docker file commands; ## 8) Security -![image-20251020174103427](D:\github\volosoft\abp\docs\en\Community-Articles\2025-10-17-Optimize-Your-App-For-Production\image-20251020174103427.png) +![Security](8.png) -### 8.1) HTTPS Everywhere Even Behind Proxy +### HTTPS Everywhere Even Behind Proxy Even if your app runs behind a reverse proxy like Nginx, Cloudflare or a load balancer, always enforce HTTPS. Why? Because internal traffic can still be captured if you don't use SSL and also cookies, HSTS, browser APIs require HTTPS. In .NET, you can easily enforce HTTPS like this: @@ -110,7 +110,7 @@ app.UseHttpsRedirection(); -### 8.2) Use HSTS in Production +### Use HSTS in Production HSTS (HTTP Strict Transport Security) tells browsers: @@ -127,7 +127,7 @@ if (!app.Environment.IsDevelopment()) When you use HSTS, it sends browser this HTTP header: ` Strict-Transport-Security: max-age=31536000; includeSubDomains`. Browser will remember this setting for 1 year (31,536,000 seconds) that this site must only use HTTPS. And `includeSubDomains` option applies the rule to all subdomains as well (eg: `api.abp.io`, `cdn.abp.io`, `account.abp.io` etc..) -### 8.3) Store Secrets on Environment Variables or Secret Stores +### Store Secrets on Environment Variables or Secret Stores Never store passwords, connection strings, or API keys in your code or Git. Then where should we keep them? @@ -147,7 +147,7 @@ Or **Secret stores** like: Azure Key Vault, AWS Secrets Manager, HashiCorp Vault -### 8.4) Add Rate-Limiting to Public Endpoints +### Add Rate-Limiting to Public Endpoints Don't forget there'll be not naive guys who will use your app! We've many times faced this issue in the past on our public front-facing websites. So protect your public APIs from abuse, bots, and DDoS. Use rate-limiting!!! Stop brute-force attacks, prevent your resources from exhaustion... @@ -167,7 +167,7 @@ app.UseRateLimiter(); - Also there's an open-source rate-limiting library -> [github.com/stefanprodan/AspNetCoreRateLimit](https://github.com/stefanprodan/AspNetCoreRateLimit) - Another one -> [nuget.org/packages/Polly.RateLimiting](https://www.nuget.org/packages/Polly.RateLimiting) -### 8.5) Secure Cookies +### Secure Cookies Cookies are often good targets for attacks. You must secure them properly otherwise you can face cookie stealing or CSRF attack. @@ -187,9 +187,9 @@ options.Cookie.SameSite = SameSiteMode.Strict; // or Lax ## 9) Startup/Cold Start -![image-20251020174425706](D:\github\volosoft\abp\docs\en\Community-Articles\2025-10-17-Optimize-Your-App-For-Production\image-20251020174425706.png) +![Cold Start / Startup](9.png) -### 9.1) Keep Tiered JIT On +### Keep Tiered JIT On The **JIT (Just-In-Time) compiler** converts your app’s Intermediate Language (IL) into native CPU instructions when the code runs. _Tiered JIT_ means the runtime uses 2 stages of compilation. Actually this setting is enabled by default in modern .NET. So just keep it on. @@ -201,7 +201,7 @@ The **JIT (Just-In-Time) compiler** converts your app’s Intermediate Language -### 9.2) **Use PGO (Profile-Guided Optimization)** +### Use PGO (Profile-Guided Optimization) PGO lets .NET learn from real usage of your app. It profiles which functions are used most often, then re-optimizes the build for that pattern. You can think of it as the runtime saying: @@ -215,7 +215,7 @@ In .NET 8+, you don’t have to manually enable PGO (Profile-Guided Optimization ## 10) Graceful Shutdown -![image-20251020174712659](D:\github\volosoft\abp\docs\en\Community-Articles\2025-10-17-Optimize-Your-App-For-Production\image-20251020174712659.png) +![Shutdown](10.png) When we break up with our lover, we often argue and regret it later. When an application breaks up with an operating system, it should be done well 😘 ... When your app stops, maybe you deploy a new version or Kubernetes restarts a pod... the OS sends a signal called `SIGTERM` (terminate). @@ -237,7 +237,7 @@ On K8s, set `terminationGracePeriodSeconds` and wire **readiness**/startup probe ## 11) Load Test -![image-20251020180232079](D:\github\volosoft\abp\docs\en\Community-Articles\2025-10-17-Optimize-Your-App-For-Production\image-20251020180232079.png) +![Load Test](11.png) Sometimes arguing with our lover is good. We can see her/his face before marrying 😀 Use **k6** or **bombardier** and test with realistic payloads and prod-like limits. Don't be surprise later when your app is running on prod! These topics should be tested: `CPU %` , `Time in GC` , `LOH Allocations` , `ThreadPool Queue Length` and `Socket Exhaustion`. @@ -255,4 +255,4 @@ Sometimes arguing with our lover is good. We can see her/his face before marryin - 7K stars on GitHub - GitHub address: https://github.com/codesenberg/bombardier -[![image-20251020175737615](D:\github\volosoft\abp\docs\en\Community-Articles\2025-10-17-Optimize-Your-App-For-Production\image-20251020175737615.png)](https://trends.google.com/trends/explore?cat=31&q=bombardier%20%2B%20benchmarking,k6%20%2B%20benchmarking) +[![Bombardier vs K6](11_1.png)](https://trends.google.com/trends/explore?cat=31&q=bombardier%20%2B%20benchmarking,k6%20%2B%20benchmarking) diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020173353352.jpg b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020173353352.jpg deleted file mode 100644 index 209eec8005..0000000000 Binary files a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020173353352.jpg and /dev/null differ diff --git a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020181303926.png b/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020181303926.png deleted file mode 100644 index 26ea05af42..0000000000 Binary files a/docs/en/Community-Articles/2025-10-17-Optimize-Your-App-For-Production/image-20251020181303926.png and /dev/null differ