@ngxtm/devkit 3.4.0 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/rules/README.md +141 -0
- package/rules/dart/best-practices/SKILL.md +23 -0
- package/rules/dart/language/SKILL.md +52 -0
- package/rules/dart/tooling/SKILL.md +43 -0
- package/rules/dotnet/aspnet-core/SKILL.md +92 -0
- package/rules/dotnet/aspnet-core/references/REFERENCE.md +335 -0
- package/rules/dotnet/best-practices/SKILL.md +101 -0
- package/rules/dotnet/best-practices/references/REFERENCE.md +256 -0
- package/rules/dotnet/blazor/SKILL.md +146 -0
- package/rules/dotnet/blazor/references/REFERENCE.md +392 -0
- package/rules/dotnet/language/SKILL.md +82 -0
- package/rules/dotnet/language/references/REFERENCE.md +222 -0
- package/rules/dotnet/patterns.rule.md +388 -0
- package/rules/dotnet/razor-pages/SKILL.md +124 -0
- package/rules/dotnet/razor-pages/references/REFERENCE.md +321 -0
- package/rules/dotnet/security/SKILL.md +89 -0
- package/rules/dotnet/security/references/REFERENCE.md +295 -0
- package/rules/dotnet/tooling/SKILL.md +92 -0
- package/rules/dotnet/tooling/references/REFERENCE.md +300 -0
- package/rules/flutter/auto-route-navigation/SKILL.md +43 -0
- package/rules/flutter/auto-route-navigation/references/REFERENCE.md +19 -0
- package/rules/flutter/auto-route-navigation/references/router-config.md +62 -0
- package/rules/flutter/bloc-state-management/SKILL.md +64 -0
- package/rules/flutter/bloc-state-management/references/REFERENCE.md +20 -0
- package/rules/flutter/bloc-state-management/references/auth-bloc-example.md +52 -0
- package/rules/flutter/bloc-state-management/references/equatable-usage.md +56 -0
- package/rules/flutter/bloc-state-management/references/property-based-state.md +68 -0
- package/rules/flutter/bloc.rule.md +76 -0
- package/rules/flutter/cicd/SKILL.md +48 -0
- package/rules/flutter/cicd/references/advanced-workflow.md +66 -0
- package/rules/flutter/cicd/references/fastlane.md +139 -0
- package/rules/flutter/cicd/references/github-actions.md +59 -0
- package/rules/flutter/dependency-injection/SKILL.md +42 -0
- package/rules/flutter/dependency-injection/references/REFERENCE.md +15 -0
- package/rules/flutter/dependency-injection/references/modules.md +37 -0
- package/rules/flutter/error-handling/SKILL.md +32 -0
- package/rules/flutter/error-handling/references/REFERENCE.md +19 -0
- package/rules/flutter/error-handling/references/error-mapping.md +31 -0
- package/rules/flutter/feature-based-clean-architecture/SKILL.md +46 -0
- package/rules/flutter/feature-based-clean-architecture/references/REFERENCE.md +14 -0
- package/rules/flutter/feature-based-clean-architecture/references/folder-structure.md +36 -0
- package/rules/flutter/getx-navigation/SKILL.md +70 -0
- package/rules/flutter/getx-navigation/references/app-pages.md +40 -0
- package/rules/flutter/getx-navigation/references/middleware-example.md +29 -0
- package/rules/flutter/getx-state-management/SKILL.md +76 -0
- package/rules/flutter/getx-state-management/references/binding-example.md +32 -0
- package/rules/flutter/getx-state-management/references/reactive-vs-simple.md +39 -0
- package/rules/flutter/go-router-navigation/SKILL.md +57 -0
- package/rules/flutter/idiomatic-flutter/SKILL.md +20 -0
- package/rules/flutter/layer-based-clean-architecture/SKILL.md +50 -0
- package/rules/flutter/layer-based-clean-architecture/references/REFERENCE.md +60 -0
- package/rules/flutter/layer-based-clean-architecture/references/repository-mapping.md +50 -0
- package/rules/flutter/localization/SKILL.md +50 -0
- package/rules/flutter/localization/references/REFERENCE.md +48 -0
- package/rules/flutter/localization/references/sheet-loader.md +33 -0
- package/rules/flutter/navigator-v1-navigation/SKILL.md +71 -0
- package/rules/flutter/navigator-v1-navigation/references/on-generate-route.md +48 -0
- package/rules/flutter/performance/SKILL.md +24 -0
- package/rules/flutter/retrofit-networking/SKILL.md +51 -0
- package/rules/flutter/retrofit-networking/references/REFERENCE.md +19 -0
- package/rules/flutter/retrofit-networking/references/token-refresh.md +40 -0
- package/rules/flutter/riverpod-state-management/SKILL.md +53 -0
- package/rules/flutter/riverpod-state-management/references/architecture.md +124 -0
- package/rules/flutter/riverpod-state-management/references/best-practices.md +89 -0
- package/rules/flutter/riverpod-state-management/references/testing.md +73 -0
- package/rules/flutter/riverpod.rule.md +78 -0
- package/rules/flutter/security/SKILL.md +33 -0
- package/rules/flutter/security/references/REFERENCE.md +15 -0
- package/rules/flutter/security/references/network-security.md +28 -0
- package/rules/flutter/testing/SKILL.md +44 -0
- package/rules/flutter/testing/references/REFERENCE.md +21 -0
- package/rules/flutter/testing/references/bloc-testing.md +38 -0
- package/rules/flutter/testing/references/integration-testing.md +128 -0
- package/rules/flutter/testing/references/robot-pattern.md +82 -0
- package/rules/flutter/testing/references/unit-testing.md +130 -0
- package/rules/flutter/testing/references/widget-testing.md +120 -0
- package/rules/flutter/widgets/SKILL.md +37 -0
- package/rules/golang/chi-router/SKILL.md +219 -0
- package/rules/golang/chi-router/references/REFERENCE.md +13 -0
- package/rules/golang/chi-router/references/routing-patterns.md +205 -0
- package/rules/golang/cobra-cli/SKILL.md +227 -0
- package/rules/golang/cobra-cli/references/REFERENCE.md +13 -0
- package/rules/golang/cobra-cli/references/command-patterns.md +224 -0
- package/rules/golang/core/SKILL.md +210 -0
- package/rules/golang/core/references/REFERENCE.md +14 -0
- package/rules/golang/core/references/concurrency-patterns.md +114 -0
- package/rules/golang/core/references/error-handling.md +87 -0
- package/rules/golang/echo-framework/SKILL.md +215 -0
- package/rules/golang/echo-framework/references/REFERENCE.md +14 -0
- package/rules/golang/echo-framework/references/middleware-patterns.md +141 -0
- package/rules/golang/echo-framework/references/routing-patterns.md +140 -0
- package/rules/golang/ent-orm/SKILL.md +239 -0
- package/rules/golang/ent-orm/references/REFERENCE.md +13 -0
- package/rules/golang/ent-orm/references/schema-patterns.md +255 -0
- package/rules/golang/fiber-framework/SKILL.md +196 -0
- package/rules/golang/fiber-framework/references/REFERENCE.md +13 -0
- package/rules/golang/fiber-framework/references/routing-patterns.md +191 -0
- package/rules/golang/gin-framework/SKILL.md +205 -0
- package/rules/golang/gin-framework/references/REFERENCE.md +14 -0
- package/rules/golang/gin-framework/references/middleware-patterns.md +119 -0
- package/rules/golang/gorm-orm/SKILL.md +196 -0
- package/rules/golang/gorm-orm/references/REFERENCE.md +14 -0
- package/rules/golang/gorm-orm/references/model-definitions.md +167 -0
- package/rules/golang/gorm-orm/references/query-patterns.md +161 -0
- package/rules/golang/grpc/SKILL.md +231 -0
- package/rules/golang/grpc/references/REFERENCE.md +13 -0
- package/rules/golang/grpc/references/service-patterns.md +276 -0
- package/rules/golang/testify/SKILL.md +239 -0
- package/rules/golang/testify/references/REFERENCE.md +13 -0
- package/rules/golang/testify/references/assert-patterns.md +170 -0
- package/rules/golang/validator/SKILL.md +234 -0
- package/rules/golang/validator/references/REFERENCE.md +13 -0
- package/rules/golang/validator/references/validation-tags.md +211 -0
- package/rules/golang/viper-config/SKILL.md +244 -0
- package/rules/golang/viper-config/references/REFERENCE.md +13 -0
- package/rules/golang/viper-config/references/config-loading.md +181 -0
- package/rules/golang/wire-di/SKILL.md +243 -0
- package/rules/golang/wire-di/references/REFERENCE.md +13 -0
- package/rules/golang/wire-di/references/provider-patterns.md +193 -0
- package/rules/golang/zap-logging/SKILL.md +203 -0
- package/rules/golang/zap-logging/references/REFERENCE.md +13 -0
- package/rules/golang/zap-logging/references/logger-config.md +165 -0
- package/rules/java/build-gradle/SKILL.md +92 -0
- package/rules/java/build-gradle/references/REFERENCE.md +14 -0
- package/rules/java/build-gradle/references/kotlin-dsl.md +118 -0
- package/rules/java/build-gradle/references/task-configuration.md +132 -0
- package/rules/java/build-maven/SKILL.md +86 -0
- package/rules/java/build-maven/references/REFERENCE.md +14 -0
- package/rules/java/build-maven/references/dependency-management.md +111 -0
- package/rules/java/build-maven/references/lifecycle-phases.md +114 -0
- package/rules/java/graalvm-native/SKILL.md +105 -0
- package/rules/java/graalvm-native/references/REFERENCE.md +12 -0
- package/rules/java/java-collections-streams/SKILL.md +148 -0
- package/rules/java/java-collections-streams/references/REFERENCE.md +15 -0
- package/rules/java/java-collections-streams/references/collectors-patterns.md +178 -0
- package/rules/java/java-collections-streams/references/stream-pipelines.md +165 -0
- package/rules/java/java-concurrency/SKILL.md +187 -0
- package/rules/java/java-concurrency/references/REFERENCE.md +17 -0
- package/rules/java/java-concurrency/references/completable-future.md +165 -0
- package/rules/java/java-concurrency/references/executor-patterns.md +176 -0
- package/rules/java/java-concurrency/references/virtual-threads.md +190 -0
- package/rules/java/java-core-language/SKILL.md +121 -0
- package/rules/java/java-core-language/references/REFERENCE.md +15 -0
- package/rules/java/java-core-language/references/jvm-memory-model.md +160 -0
- package/rules/java/java-core-language/references/modern-java-features.md +168 -0
- package/rules/java/java-project-structure/SKILL.md +195 -0
- package/rules/java/java-project-structure/references/REFERENCE.md +15 -0
- package/rules/java/java-project-structure/references/maven-project-layout.md +199 -0
- package/rules/java/java-project-structure/references/module-system.md +159 -0
- package/rules/java/micronaut-core/SKILL.md +99 -0
- package/rules/java/micronaut-core/references/REFERENCE.md +12 -0
- package/rules/java/micronaut-reactive/SKILL.md +68 -0
- package/rules/java/micronaut-reactive/references/REFERENCE.md +12 -0
- package/rules/java/quarkus-core/SKILL.md +85 -0
- package/rules/java/quarkus-core/references/REFERENCE.md +12 -0
- package/rules/java/quarkus-reactive/SKILL.md +67 -0
- package/rules/java/quarkus-reactive/references/REFERENCE.md +12 -0
- package/rules/java/spring-batch/SKILL.md +102 -0
- package/rules/java/spring-batch/references/REFERENCE.md +12 -0
- package/rules/java/spring-boot-architecture/SKILL.md +206 -0
- package/rules/java/spring-boot-architecture/references/REFERENCE.md +15 -0
- package/rules/java/spring-boot-architecture/references/auto-configuration.md +158 -0
- package/rules/java/spring-boot-architecture/references/configuration-properties.md +202 -0
- package/rules/java/spring-boot-web/SKILL.md +217 -0
- package/rules/java/spring-boot-web/references/REFERENCE.md +17 -0
- package/rules/java/spring-cloud/SKILL.md +109 -0
- package/rules/java/spring-cloud/references/REFERENCE.md +13 -0
- package/rules/java/spring-data-jpa/SKILL.md +241 -0
- package/rules/java/spring-data-jpa/references/REFERENCE.md +16 -0
- package/rules/java/spring-security/SKILL.md +161 -0
- package/rules/java/spring-security/references/REFERENCE.md +16 -0
- package/rules/java/spring-security/references/jwt-auth-flow.md +213 -0
- package/rules/java/testing-junit-mockito/SKILL.md +135 -0
- package/rules/java/testing-junit-mockito/references/REFERENCE.md +15 -0
- package/rules/java/testing-junit-mockito/references/junit5-patterns.md +159 -0
- package/rules/java/testing-junit-mockito/references/mockito-patterns.md +148 -0
- package/rules/java/testing-junit-mockito/references/spring-boot-testing.md +152 -0
- package/rules/javascript/best-practices/SKILL.md +64 -0
- package/rules/javascript/best-practices/references/REFERENCE.md +91 -0
- package/rules/javascript/language/SKILL.md +71 -0
- package/rules/javascript/language/references/REFERENCE.md +106 -0
- package/rules/javascript/tooling/SKILL.md +60 -0
- package/rules/javascript/tooling/references/REFERENCE.md +107 -0
- package/rules/metadata.json +54 -0
- package/rules/nestjs/api-standards/SKILL.md +47 -0
- package/rules/nestjs/api-standards/references/pagination-wrapper.md +87 -0
- package/rules/nestjs/architecture/SKILL.md +68 -0
- package/rules/nestjs/architecture/references/dynamic-module.md +53 -0
- package/rules/nestjs/caching/SKILL.md +51 -0
- package/rules/nestjs/caching/references/REFERENCE.md +13 -0
- package/rules/nestjs/caching/references/cache-patterns.md +183 -0
- package/rules/nestjs/configuration/SKILL.md +41 -0
- package/rules/nestjs/configuration/references/REFERENCE.md +13 -0
- package/rules/nestjs/configuration/references/config-patterns.md +184 -0
- package/rules/nestjs/controllers-services/SKILL.md +63 -0
- package/rules/nestjs/controllers-services/references/REFERENCE.md +14 -0
- package/rules/nestjs/controllers-services/references/controller-patterns.md +119 -0
- package/rules/nestjs/controllers-services/references/service-patterns.md +129 -0
- package/rules/nestjs/database/SKILL.md +102 -0
- package/rules/nestjs/database/references/REFERENCE.md +14 -0
- package/rules/nestjs/database/references/typeorm-patterns.md +156 -0
- package/rules/nestjs/deployment/SKILL.md +36 -0
- package/rules/nestjs/deployment/references/REFERENCE.md +13 -0
- package/rules/nestjs/deployment/references/deployment-patterns.md +140 -0
- package/rules/nestjs/documentation/SKILL.md +64 -0
- package/rules/nestjs/documentation/references/REFERENCE.md +13 -0
- package/rules/nestjs/documentation/references/swagger-patterns.md +139 -0
- package/rules/nestjs/error-handling/SKILL.md +55 -0
- package/rules/nestjs/error-handling/references/REFERENCE.md +13 -0
- package/rules/nestjs/error-handling/references/exception-filters.md +152 -0
- package/rules/nestjs/file-uploads/SKILL.md +35 -0
- package/rules/nestjs/file-uploads/references/REFERENCE.md +13 -0
- package/rules/nestjs/file-uploads/references/upload-patterns.md +125 -0
- package/rules/nestjs/observability/SKILL.md +39 -0
- package/rules/nestjs/observability/references/REFERENCE.md +13 -0
- package/rules/nestjs/observability/references/logging-metrics.md +175 -0
- package/rules/nestjs/performance/SKILL.md +60 -0
- package/rules/nestjs/performance/references/REFERENCE.md +13 -0
- package/rules/nestjs/performance/references/performance-patterns.md +107 -0
- package/rules/nestjs/real-time/SKILL.md +45 -0
- package/rules/nestjs/real-time/references/REFERENCE.md +13 -0
- package/rules/nestjs/real-time/references/websocket-patterns.md +121 -0
- package/rules/nestjs/scheduling/SKILL.md +39 -0
- package/rules/nestjs/scheduling/references/REFERENCE.md +13 -0
- package/rules/nestjs/scheduling/references/scheduling-patterns.md +137 -0
- package/rules/nestjs/search/SKILL.md +41 -0
- package/rules/nestjs/search/references/REFERENCE.md +13 -0
- package/rules/nestjs/search/references/search-patterns.md +137 -0
- package/rules/nestjs/security/SKILL.md +87 -0
- package/rules/nestjs/security/references/REFERENCE.md +14 -0
- package/rules/nestjs/security/references/authentication.md +151 -0
- package/rules/nestjs/testing/SKILL.md +40 -0
- package/rules/nestjs/testing/references/REFERENCE.md +14 -0
- package/rules/nestjs/testing/references/unit-testing.md +179 -0
- package/rules/nestjs/transport/SKILL.md +45 -0
- package/rules/nestjs/transport/references/REFERENCE.md +13 -0
- package/rules/nestjs/transport/references/microservices-patterns.md +170 -0
- package/rules/nextjs/app-router/SKILL.md +46 -0
- package/rules/nextjs/app-router/references/REFERENCE.md +14 -0
- package/rules/nextjs/app-router/references/routing-patterns.md +182 -0
- package/rules/nextjs/architecture/SKILL.md +44 -0
- package/rules/nextjs/architecture/references/fsd-structure.md +77 -0
- package/rules/nextjs/authentication/SKILL.md +29 -0
- package/rules/nextjs/authentication/references/auth-implementation.md +73 -0
- package/rules/nextjs/caching/SKILL.md +66 -0
- package/rules/nextjs/caching/references/REFERENCE.md +13 -0
- package/rules/nextjs/caching/references/cache-strategies.md +168 -0
- package/rules/nextjs/data-access-layer/SKILL.md +33 -0
- package/rules/nextjs/data-access-layer/references/patterns.md +66 -0
- package/rules/nextjs/data-fetching/SKILL.md +59 -0
- package/rules/nextjs/data-fetching/references/REFERENCE.md +13 -0
- package/rules/nextjs/data-fetching/references/fetch-patterns.md +160 -0
- package/rules/nextjs/internationalization/SKILL.md +105 -0
- package/rules/nextjs/internationalization/references/REFERENCE.md +13 -0
- package/rules/nextjs/internationalization/references/i18n-patterns.md +180 -0
- package/rules/nextjs/optimization/SKILL.md +64 -0
- package/rules/nextjs/optimization/references/REFERENCE.md +13 -0
- package/rules/nextjs/optimization/references/optimization-patterns.md +190 -0
- package/rules/nextjs/rendering/SKILL.md +91 -0
- package/rules/nextjs/rendering/references/REFERENCE.md +13 -0
- package/rules/nextjs/rendering/references/rendering-modes.md +163 -0
- package/rules/nextjs/server-actions/SKILL.md +46 -0
- package/rules/nextjs/server-actions/references/REFERENCE.md +13 -0
- package/rules/nextjs/server-actions/references/action-patterns.md +188 -0
- package/rules/nextjs/server-components/SKILL.md +52 -0
- package/rules/nextjs/server-components/references/REFERENCE.md +13 -0
- package/rules/nextjs/server-components/references/component-patterns.md +175 -0
- package/rules/nextjs/state-management/SKILL.md +73 -0
- package/rules/nextjs/state-management/references/REFERENCE.md +13 -0
- package/rules/nextjs/state-management/references/state-patterns.md +218 -0
- package/rules/nextjs/styling/SKILL.md +31 -0
- package/rules/nextjs/styling/references/implementation.md +56 -0
- package/rules/react/component-patterns/SKILL.md +66 -0
- package/rules/react/component-patterns/references/REFERENCE.md +126 -0
- package/rules/react/hooks/SKILL.md +60 -0
- package/rules/react/hooks/references/REFERENCE.md +132 -0
- package/rules/react/hooks.rule.md +79 -0
- package/rules/react/performance/SKILL.md +69 -0
- package/rules/react/performance/references/REFERENCE.md +143 -0
- package/rules/react/security/SKILL.md +46 -0
- package/rules/react/security/references/REFERENCE.md +170 -0
- package/rules/react/state-management/SKILL.md +56 -0
- package/rules/react/state-management/references/REFERENCE.md +137 -0
- package/rules/react/testing/SKILL.md +45 -0
- package/rules/react/testing/references/REFERENCE.md +149 -0
- package/rules/react/tooling/SKILL.md +39 -0
- package/rules/react/typescript/SKILL.md +53 -0
- package/rules/rust/actix-web/SKILL.md +160 -0
- package/rules/rust/actix-web/references/REFERENCE.md +13 -0
- package/rules/rust/actix-web/references/handler-patterns.md +198 -0
- package/rules/rust/async-graphql/SKILL.md +228 -0
- package/rules/rust/async-graphql/references/REFERENCE.md +13 -0
- package/rules/rust/async-graphql/references/schema-patterns.md +215 -0
- package/rules/rust/axum/SKILL.md +161 -0
- package/rules/rust/axum/references/REFERENCE.md +14 -0
- package/rules/rust/axum/references/handler-patterns.md +97 -0
- package/rules/rust/bevy/SKILL.md +206 -0
- package/rules/rust/bevy/references/REFERENCE.md +13 -0
- package/rules/rust/bevy/references/ecs-patterns.md +226 -0
- package/rules/rust/clap/SKILL.md +217 -0
- package/rules/rust/clap/references/REFERENCE.md +13 -0
- package/rules/rust/clap/references/derive-patterns.md +205 -0
- package/rules/rust/core/SKILL.md +154 -0
- package/rules/rust/core/references/REFERENCE.md +14 -0
- package/rules/rust/core/references/error-handling.md +92 -0
- package/rules/rust/diesel-orm/SKILL.md +176 -0
- package/rules/rust/diesel-orm/references/REFERENCE.md +13 -0
- package/rules/rust/diesel-orm/references/schema-patterns.md +206 -0
- package/rules/rust/rocket/SKILL.md +182 -0
- package/rules/rust/rocket/references/REFERENCE.md +13 -0
- package/rules/rust/rocket/references/handler-patterns.md +209 -0
- package/rules/rust/sea-orm/SKILL.md +230 -0
- package/rules/rust/sea-orm/references/REFERENCE.md +13 -0
- package/rules/rust/sea-orm/references/entity-patterns.md +221 -0
- package/rules/rust/serde-serialization/SKILL.md +150 -0
- package/rules/rust/serde-serialization/references/REFERENCE.md +13 -0
- package/rules/rust/serde-serialization/references/serialization-patterns.md +199 -0
- package/rules/rust/sqlx-database/SKILL.md +140 -0
- package/rules/rust/sqlx-database/references/REFERENCE.md +13 -0
- package/rules/rust/sqlx-database/references/query-patterns.md +210 -0
- package/rules/rust/tauri/SKILL.md +180 -0
- package/rules/rust/tauri/references/REFERENCE.md +13 -0
- package/rules/rust/tauri/references/command-patterns.md +209 -0
- package/rules/rust/tokio-runtime/SKILL.md +167 -0
- package/rules/rust/tokio-runtime/references/REFERENCE.md +14 -0
- package/rules/rust/tokio-runtime/references/async-patterns.md +137 -0
- package/rules/rust/tokio-runtime/references/synchronization.md +152 -0
- package/rules/rust/tonic/SKILL.md +231 -0
- package/rules/rust/tonic/references/REFERENCE.md +13 -0
- package/rules/rust/tonic/references/service-patterns.md +213 -0
- package/rules/rust/tracing/SKILL.md +214 -0
- package/rules/rust/tracing/references/REFERENCE.md +13 -0
- package/rules/rust/tracing/references/instrumentation.md +187 -0
- package/rules/typescript/best-practices/SKILL.md +108 -0
- package/rules/typescript/best-practices/references/REFERENCE.md +68 -0
- package/rules/typescript/language/SKILL.md +72 -0
- package/rules/typescript/language/references/REFERENCE.md +67 -0
- package/rules/typescript/patterns.rule.md +85 -0
- package/rules/typescript/security/SKILL.md +59 -0
- package/rules/typescript/security/references/REFERENCE.md +113 -0
- package/rules/typescript/tooling/SKILL.md +52 -0
- package/rules/typescript/tooling/references/REFERENCE.md +110 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# NestJS Logging & Metrics
|
|
2
|
+
|
|
3
|
+
## Built-in Logger
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import { Logger, Injectable } from '@nestjs/common';
|
|
7
|
+
|
|
8
|
+
@Injectable()
|
|
9
|
+
export class UsersService {
|
|
10
|
+
private readonly logger = new Logger(UsersService.name);
|
|
11
|
+
|
|
12
|
+
async findOne(id: string) {
|
|
13
|
+
this.logger.log(`Finding user ${id}`);
|
|
14
|
+
this.logger.debug('Debug info');
|
|
15
|
+
this.logger.warn('Warning message');
|
|
16
|
+
this.logger.error('Error occurred', error.stack);
|
|
17
|
+
|
|
18
|
+
return user;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Custom Logger
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { LoggerService } from '@nestjs/common';
|
|
27
|
+
import * as winston from 'winston';
|
|
28
|
+
|
|
29
|
+
export class WinstonLogger implements LoggerService {
|
|
30
|
+
private logger: winston.Logger;
|
|
31
|
+
|
|
32
|
+
constructor() {
|
|
33
|
+
this.logger = winston.createLogger({
|
|
34
|
+
level: 'info',
|
|
35
|
+
format: winston.format.combine(
|
|
36
|
+
winston.format.timestamp(),
|
|
37
|
+
winston.format.json(),
|
|
38
|
+
),
|
|
39
|
+
transports: [
|
|
40
|
+
new winston.transports.Console(),
|
|
41
|
+
new winston.transports.File({ filename: 'app.log' }),
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
log(message: string, context?: string) {
|
|
47
|
+
this.logger.info(message, { context });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
error(message: string, trace?: string, context?: string) {
|
|
51
|
+
this.logger.error(message, { trace, context });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
warn(message: string, context?: string) {
|
|
55
|
+
this.logger.warn(message, { context });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// main.ts
|
|
60
|
+
const app = await NestFactory.create(AppModule, {
|
|
61
|
+
logger: new WinstonLogger(),
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Request Logging Middleware
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
@Injectable()
|
|
69
|
+
export class LoggingMiddleware implements NestMiddleware {
|
|
70
|
+
private readonly logger = new Logger('HTTP');
|
|
71
|
+
|
|
72
|
+
use(req: Request, res: Response, next: NextFunction) {
|
|
73
|
+
const { method, originalUrl } = req;
|
|
74
|
+
const requestId = req.headers['x-request-id'] || uuid();
|
|
75
|
+
|
|
76
|
+
const start = Date.now();
|
|
77
|
+
|
|
78
|
+
res.on('finish', () => {
|
|
79
|
+
const duration = Date.now() - start;
|
|
80
|
+
this.logger.log(
|
|
81
|
+
`${method} ${originalUrl} ${res.statusCode} ${duration}ms`,
|
|
82
|
+
{ requestId },
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
next();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Health Checks
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { TerminusModule, HealthCheckService, HttpHealthIndicator, TypeOrmHealthIndicator } from '@nestjs/terminus';
|
|
95
|
+
|
|
96
|
+
@Controller('health')
|
|
97
|
+
export class HealthController {
|
|
98
|
+
constructor(
|
|
99
|
+
private health: HealthCheckService,
|
|
100
|
+
private http: HttpHealthIndicator,
|
|
101
|
+
private db: TypeOrmHealthIndicator,
|
|
102
|
+
) {}
|
|
103
|
+
|
|
104
|
+
@Get()
|
|
105
|
+
check() {
|
|
106
|
+
return this.health.check([
|
|
107
|
+
() => this.db.pingCheck('database'),
|
|
108
|
+
() => this.http.pingCheck('api', 'https://api.example.com'),
|
|
109
|
+
]);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@Get('liveness')
|
|
113
|
+
liveness() {
|
|
114
|
+
return { status: 'ok' };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@Get('readiness')
|
|
118
|
+
readiness() {
|
|
119
|
+
return this.health.check([
|
|
120
|
+
() => this.db.pingCheck('database'),
|
|
121
|
+
]);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Prometheus Metrics
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { PrometheusModule, makeCounterProvider, makeHistogramProvider } from '@willsoto/nestjs-prometheus';
|
|
130
|
+
|
|
131
|
+
@Module({
|
|
132
|
+
imports: [
|
|
133
|
+
PrometheusModule.register({
|
|
134
|
+
path: '/metrics',
|
|
135
|
+
defaultMetrics: { enabled: true },
|
|
136
|
+
}),
|
|
137
|
+
],
|
|
138
|
+
providers: [
|
|
139
|
+
makeCounterProvider({
|
|
140
|
+
name: 'http_requests_total',
|
|
141
|
+
help: 'Total HTTP requests',
|
|
142
|
+
labelNames: ['method', 'path', 'status'],
|
|
143
|
+
}),
|
|
144
|
+
makeHistogramProvider({
|
|
145
|
+
name: 'http_request_duration_seconds',
|
|
146
|
+
help: 'HTTP request duration',
|
|
147
|
+
labelNames: ['method', 'path'],
|
|
148
|
+
buckets: [0.1, 0.5, 1, 2, 5],
|
|
149
|
+
}),
|
|
150
|
+
],
|
|
151
|
+
})
|
|
152
|
+
export class MetricsModule {}
|
|
153
|
+
|
|
154
|
+
// Usage in interceptor
|
|
155
|
+
@Injectable()
|
|
156
|
+
export class MetricsInterceptor implements NestInterceptor {
|
|
157
|
+
constructor(
|
|
158
|
+
@InjectMetric('http_requests_total') private counter: Counter,
|
|
159
|
+
@InjectMetric('http_request_duration_seconds') private histogram: Histogram,
|
|
160
|
+
) {}
|
|
161
|
+
|
|
162
|
+
intercept(context: ExecutionContext, next: CallHandler) {
|
|
163
|
+
const req = context.switchToHttp().getRequest();
|
|
164
|
+
const start = Date.now();
|
|
165
|
+
|
|
166
|
+
return next.handle().pipe(
|
|
167
|
+
tap(() => {
|
|
168
|
+
const duration = (Date.now() - start) / 1000;
|
|
169
|
+
this.counter.inc({ method: req.method, path: req.path, status: 200 });
|
|
170
|
+
this.histogram.observe({ method: req.method, path: req.path }, duration);
|
|
171
|
+
}),
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: NestJS Performance
|
|
3
|
+
description: Fastify adapter, Scope management, and Compression.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [nestjs, performance, fastify]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['main.ts']
|
|
8
|
+
keywords: [FastifyAdapter, compression, SINGLETON, REQUEST scope]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Performance Tuning
|
|
12
|
+
|
|
13
|
+
## Network & Runtime
|
|
14
|
+
|
|
15
|
+
- **Adapter**: Use `FastifyAdapter` instead of Express (2x throughput).
|
|
16
|
+
- **Compression**: Enable Gzip/Brotli compression.
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
// main.ts
|
|
20
|
+
app.use(compression());
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- **Keep-Alive**: Configure `http.Agent` keep-alive settings to reuse TCP connections for upstream services.
|
|
24
|
+
|
|
25
|
+
## Scope & Dependency Injection
|
|
26
|
+
|
|
27
|
+
- **Default Scope**: Adhere to `SINGLETON` scope (default).
|
|
28
|
+
- **Request Scope**: AVOID `REQUEST` scope unless absolutely necessary.
|
|
29
|
+
- **Pro Tip**: A single request-scoped service makes its entire injection chain request-scoped.
|
|
30
|
+
- **Solution**: Use **Durable Providers** (`durable: true`) for multi-tenancy.
|
|
31
|
+
- **Lazy Loading**: Use `LazyModuleLoader` for heavyweight modules (e.g., Admin panels).
|
|
32
|
+
|
|
33
|
+
## Caching Strategy
|
|
34
|
+
|
|
35
|
+
- **Application Cache**: Use `@nestjs/cache-manager` for computation results.
|
|
36
|
+
- **Deep Dive**: See **[Caching & Redis](../caching/SKILL.md)** for L1/L2 strategies and Invalidation patterns.
|
|
37
|
+
- **HTTP Cache**: Set `Cache-Control` headers for client-side caching (CDN/Browser).
|
|
38
|
+
- **Distributed**: In microservices, use Redis store, not memory store.
|
|
39
|
+
|
|
40
|
+
## Queues & Async Processing
|
|
41
|
+
|
|
42
|
+
- **Offloading**: Never block the HTTP request for long-running tasks (Emails, Reports, webhooks).
|
|
43
|
+
- **Tool**: Use `@nestjs/bull` (BullMQ) or RabbitMQ (`@nestjs/microservices`).
|
|
44
|
+
- **Pattern**: Producer (Controller) -> Queue -> Consumer (Processor).
|
|
45
|
+
|
|
46
|
+
## Serialization
|
|
47
|
+
|
|
48
|
+
- **Warning**: `class-transformer` is CPU expensive.
|
|
49
|
+
- **Optimization**: For high-throughput READ endpoints, consider manual mapping or using `fast-json-stringify` (built-in fastify serialization) instead of interceptors.
|
|
50
|
+
|
|
51
|
+
## Database Tuning
|
|
52
|
+
|
|
53
|
+
- **Projections**: Always use `select: []` to fetch only needed columns.
|
|
54
|
+
- **N+1**: Prevent N+1 queries by using `relations` carefully or `DataLoader` for Graph/Field resolvers.
|
|
55
|
+
- **Connection Pooling**: Configure pool size (e.g., `pool: { min: 2, max: 10 }`) in config to match DB limits.
|
|
56
|
+
|
|
57
|
+
## Profiling & Scaling
|
|
58
|
+
|
|
59
|
+
- **Offloading**: Move CPU-heavy tasks (Image processing, Crypto) to `worker_threads`.
|
|
60
|
+
- **Clustering**: For non-containerized environments, use `ClusterModule` to utilize all CPU cores. In K8s, prefer ReplicaSets.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# NestJS Performance References
|
|
2
|
+
|
|
3
|
+
## References
|
|
4
|
+
|
|
5
|
+
- [**Performance Patterns**](performance-patterns.md) - Caching, compression, clustering
|
|
6
|
+
|
|
7
|
+
## Quick Checks
|
|
8
|
+
|
|
9
|
+
- [ ] Enable compression middleware
|
|
10
|
+
- [ ] Use caching strategically
|
|
11
|
+
- [ ] Implement request/response interceptors
|
|
12
|
+
- [ ] Enable clustering for multi-core
|
|
13
|
+
- [ ] Profile and optimize hot paths
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# NestJS Performance Patterns
|
|
2
|
+
|
|
3
|
+
## Compression
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import compression from 'compression';
|
|
7
|
+
|
|
8
|
+
async function bootstrap() {
|
|
9
|
+
const app = await NestFactory.create(AppModule);
|
|
10
|
+
app.use(compression());
|
|
11
|
+
await app.listen(3000);
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Response Caching Interceptor
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { CacheInterceptor, CacheKey, CacheTTL } from '@nestjs/cache-manager';
|
|
19
|
+
|
|
20
|
+
@Controller('products')
|
|
21
|
+
@UseInterceptors(CacheInterceptor)
|
|
22
|
+
export class ProductsController {
|
|
23
|
+
@Get()
|
|
24
|
+
@CacheKey('all-products')
|
|
25
|
+
@CacheTTL(300) // 5 minutes
|
|
26
|
+
findAll() {
|
|
27
|
+
return this.productsService.findAll();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Request Timeout
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
|
|
36
|
+
import { timeout } from 'rxjs/operators';
|
|
37
|
+
|
|
38
|
+
@Injectable()
|
|
39
|
+
export class TimeoutInterceptor implements NestInterceptor {
|
|
40
|
+
intercept(context: ExecutionContext, next: CallHandler) {
|
|
41
|
+
return next.handle().pipe(timeout(5000));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Database Query Optimization
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
@Injectable()
|
|
50
|
+
export class UsersService {
|
|
51
|
+
// Pagination
|
|
52
|
+
async findAll(page = 1, limit = 20) {
|
|
53
|
+
return this.userRepo.find({
|
|
54
|
+
skip: (page - 1) * limit,
|
|
55
|
+
take: limit,
|
|
56
|
+
select: ['id', 'name', 'email'], // Select only needed fields
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Eager loading
|
|
61
|
+
async findWithOrders(id: string) {
|
|
62
|
+
return this.userRepo.findOne({
|
|
63
|
+
where: { id },
|
|
64
|
+
relations: ['orders', 'orders.items'],
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Clustering
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
// main.ts
|
|
74
|
+
import cluster from 'cluster';
|
|
75
|
+
import os from 'os';
|
|
76
|
+
|
|
77
|
+
if (cluster.isPrimary) {
|
|
78
|
+
const numCPUs = os.cpus().length;
|
|
79
|
+
for (let i = 0; i < numCPUs; i++) {
|
|
80
|
+
cluster.fork();
|
|
81
|
+
}
|
|
82
|
+
cluster.on('exit', (worker) => {
|
|
83
|
+
console.log(`Worker ${worker.process.pid} died`);
|
|
84
|
+
cluster.fork();
|
|
85
|
+
});
|
|
86
|
+
} else {
|
|
87
|
+
bootstrap();
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Lazy Loading Modules
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
@Module({})
|
|
95
|
+
export class AppModule {
|
|
96
|
+
static forRoot(): DynamicModule {
|
|
97
|
+
return {
|
|
98
|
+
module: AppModule,
|
|
99
|
+
imports: [
|
|
100
|
+
LazyModuleLoader.forFeature([
|
|
101
|
+
() => import('./reports/reports.module').then(m => m.ReportsModule),
|
|
102
|
+
]),
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: NestJS Real-Time
|
|
3
|
+
description: WebSocket and SSE selection strategies and scaling.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [nestjs, websockets, sse, socket.io]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**/*.gateway.ts', '**/*.controller.ts']
|
|
8
|
+
keywords: [WebSocketGateway, SubscribeMessage, Sse, Socket.io]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Real-Time & WebSockets
|
|
12
|
+
|
|
13
|
+
## Selection Strategy (Critical)
|
|
14
|
+
|
|
15
|
+
- **WebSockets (Bi-directional)**: Use for Chat, Multiplayer Games, Collaborative Editing.
|
|
16
|
+
- _High Complexity_: Requires custom scaling (Redis Adapter) and sticky sessions (sometimes).
|
|
17
|
+
- **Server-Sent Events (SSE) (Uni-directional)**: Use for Notifications, Live Feeds, Tickers, CI Log streaming.
|
|
18
|
+
- _Low Complexity_: Standard HTTP. Works with standard Load Balancers. Easy to secure.
|
|
19
|
+
- _NestJS_: Use `@Sse('route')` returning `Observable<MessageEvent>`.
|
|
20
|
+
- **Long Polling**: Use **only** as a fallback or for extremely low-frequency updates (e.g., job status check every 10m).
|
|
21
|
+
- _Impact_: High header overhead. Blocks threads if not handled carefully.
|
|
22
|
+
|
|
23
|
+
## WebSockets Implementation
|
|
24
|
+
|
|
25
|
+
- **Socket.io**: Default choice. Features "Rooms", "Namespaces", and automatic reconnection. Heavy protocol.
|
|
26
|
+
- **Fastify/WS**: Use `ws` adapter if performance is critical (e.g., high-frequency trading updates) and you don't need "Rooms" logic.
|
|
27
|
+
|
|
28
|
+
## Scaling (Critical)
|
|
29
|
+
|
|
30
|
+
- **WebSockets**: In K8s, a client connects to Pod A. If Pod B emits an event, the client won't receive it.
|
|
31
|
+
- **Solution**: **Redis Adapter** (`@socket.io/redis-adapter`). Every pod publishes to Redis; Redis distributes to all other pods.
|
|
32
|
+
- **SSE**: Stateless. No special adapter needed, but be aware of **Connection Limits** (6 concurrent connections per domain in HTTP/1.1; virtually unlimited in HTTP/2).
|
|
33
|
+
- **Rule**: Must use **HTTP/2** for SSE at scale.
|
|
34
|
+
|
|
35
|
+
## Security
|
|
36
|
+
|
|
37
|
+
- **Handshake Auth**: Standard HTTP Guards don't trigger on Ws connection efficiently.
|
|
38
|
+
- **Pattern**: Validate JWT during the `handleConnection()` lifecycle method. Disconnect immediately if invalid.
|
|
39
|
+
- **Rate Limiting**: Sockets are expensive. Apply strict throttling on "Message" events to prevent flooding.
|
|
40
|
+
|
|
41
|
+
## Architecture
|
|
42
|
+
|
|
43
|
+
- **Gateway != Service**: The `WebSocketGateway` should **only** handle client comms (Join Room, Ack message).
|
|
44
|
+
- **Rule**: Delegate business logic to a Service or Command Bus.
|
|
45
|
+
- **Events**: Use `AsyncApi` or `SocketApi` decorators (from community packages) to document WS events similarly to OpenAPI.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# NestJS Real-time References
|
|
2
|
+
|
|
3
|
+
## References
|
|
4
|
+
|
|
5
|
+
- [**WebSocket Patterns**](websocket-patterns.md) - Gateways, events, rooms
|
|
6
|
+
|
|
7
|
+
## Quick Checks
|
|
8
|
+
|
|
9
|
+
- [ ] Use @WebSocketGateway decorator
|
|
10
|
+
- [ ] Handle connection/disconnection
|
|
11
|
+
- [ ] Rooms for grouped messaging
|
|
12
|
+
- [ ] Authentication via handshake
|
|
13
|
+
- [ ] Proper error handling
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# NestJS WebSocket Patterns
|
|
2
|
+
|
|
3
|
+
## Gateway Setup
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
import {
|
|
7
|
+
WebSocketGateway,
|
|
8
|
+
WebSocketServer,
|
|
9
|
+
SubscribeMessage,
|
|
10
|
+
OnGatewayConnection,
|
|
11
|
+
OnGatewayDisconnect,
|
|
12
|
+
ConnectedSocket,
|
|
13
|
+
MessageBody,
|
|
14
|
+
} from '@nestjs/websockets';
|
|
15
|
+
import { Server, Socket } from 'socket.io';
|
|
16
|
+
|
|
17
|
+
@WebSocketGateway({
|
|
18
|
+
cors: { origin: '*' },
|
|
19
|
+
namespace: '/chat',
|
|
20
|
+
})
|
|
21
|
+
export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
|
|
22
|
+
@WebSocketServer()
|
|
23
|
+
server: Server;
|
|
24
|
+
|
|
25
|
+
handleConnection(client: Socket) {
|
|
26
|
+
console.log(`Client connected: ${client.id}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
handleDisconnect(client: Socket) {
|
|
30
|
+
console.log(`Client disconnected: ${client.id}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@SubscribeMessage('message')
|
|
34
|
+
handleMessage(
|
|
35
|
+
@ConnectedSocket() client: Socket,
|
|
36
|
+
@MessageBody() data: { room: string; message: string },
|
|
37
|
+
) {
|
|
38
|
+
this.server.to(data.room).emit('message', {
|
|
39
|
+
sender: client.id,
|
|
40
|
+
message: data.message,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@SubscribeMessage('join')
|
|
45
|
+
handleJoin(
|
|
46
|
+
@ConnectedSocket() client: Socket,
|
|
47
|
+
@MessageBody() room: string,
|
|
48
|
+
) {
|
|
49
|
+
client.join(room);
|
|
50
|
+
client.emit('joined', room);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Authentication
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
@WebSocketGateway()
|
|
59
|
+
export class AuthenticatedGateway implements OnGatewayConnection {
|
|
60
|
+
constructor(private authService: AuthService) {}
|
|
61
|
+
|
|
62
|
+
async handleConnection(client: Socket) {
|
|
63
|
+
try {
|
|
64
|
+
const token = client.handshake.auth.token;
|
|
65
|
+
const user = await this.authService.validateToken(token);
|
|
66
|
+
client.data.user = user;
|
|
67
|
+
} catch {
|
|
68
|
+
client.disconnect();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@SubscribeMessage('protected-event')
|
|
73
|
+
handleProtected(@ConnectedSocket() client: Socket) {
|
|
74
|
+
const user = client.data.user;
|
|
75
|
+
return { user: user.name };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Broadcasting
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
@Injectable()
|
|
84
|
+
export class NotificationsService {
|
|
85
|
+
constructor(
|
|
86
|
+
@Inject('CHAT_GATEWAY')
|
|
87
|
+
private gateway: ChatGateway,
|
|
88
|
+
) {}
|
|
89
|
+
|
|
90
|
+
// Broadcast to all
|
|
91
|
+
broadcastToAll(event: string, data: any) {
|
|
92
|
+
this.gateway.server.emit(event, data);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// To specific room
|
|
96
|
+
broadcastToRoom(room: string, event: string, data: any) {
|
|
97
|
+
this.gateway.server.to(room).emit(event, data);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// To specific client
|
|
101
|
+
sendToClient(clientId: string, event: string, data: any) {
|
|
102
|
+
this.gateway.server.to(clientId).emit(event, data);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Module Setup
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
@Module({
|
|
111
|
+
providers: [
|
|
112
|
+
ChatGateway,
|
|
113
|
+
{
|
|
114
|
+
provide: 'CHAT_GATEWAY',
|
|
115
|
+
useExisting: ChatGateway,
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
exports: ['CHAT_GATEWAY'],
|
|
119
|
+
})
|
|
120
|
+
export class WebSocketModule {}
|
|
121
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: NestJS Scheduling
|
|
3
|
+
description: Distributed cron jobs and locking patterns.
|
|
4
|
+
metadata:
|
|
5
|
+
labels: [nestjs, cron, scheduling, redis]
|
|
6
|
+
triggers:
|
|
7
|
+
files: ['**/*.service.ts']
|
|
8
|
+
keywords: ["@Cron, CronExpression, ScheduleModule"]
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Task Scheduling & Jobs
|
|
12
|
+
|
|
13
|
+
## Distributed Cron (Critical)
|
|
14
|
+
|
|
15
|
+
- **Problem**: `@Cron()` runs on **every** instance. In K8s with 3 pods, your "Daily Report" runs 3 times.
|
|
16
|
+
- **Solution**: **Distributed Locking** using Redis.
|
|
17
|
+
- **Pattern**: Using a decorator to wrap the cron method.
|
|
18
|
+
- **Logic**: `SET resource_name my_random_value NX PX 30000` (Redis Atomic Set).
|
|
19
|
+
|
|
20
|
+
## Cron Decorator Pattern
|
|
21
|
+
|
|
22
|
+
- **Implementation**:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
@Cron(CronExpression.EVERY_MINUTE)
|
|
26
|
+
@DistributedLock({ key: 'send_emails', ttl: 5000 })
|
|
27
|
+
async handleCron() {
|
|
28
|
+
// Only runs if lock acquired
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- **Tools**: Use `nestjs-redlock` or custom Redis wrapper via `redlock` library.
|
|
33
|
+
|
|
34
|
+
## Job Robustness
|
|
35
|
+
|
|
36
|
+
- **Isolation**: Never perform heavy processing inside the Cron handler.
|
|
37
|
+
- **Pattern**: Cron -> Push Job ID to Queue (BullMQ) -> Worker processes it.
|
|
38
|
+
- **Why**: Cron schedulers can get blocked by the Event Loop; Workers are scalable.
|
|
39
|
+
- **Error Handling**: Wrap ALL cron logic in `try/catch`. Uncaught exceptions in a Cron job can crash the entire Node process.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# NestJS Scheduling References
|
|
2
|
+
|
|
3
|
+
## References
|
|
4
|
+
|
|
5
|
+
- [**Scheduling Patterns**](scheduling-patterns.md) - Cron jobs, intervals, timeouts, queues
|
|
6
|
+
|
|
7
|
+
## Quick Checks
|
|
8
|
+
|
|
9
|
+
- [ ] Use @Cron for recurring tasks
|
|
10
|
+
- [ ] Use queues for heavy background jobs
|
|
11
|
+
- [ ] Handle job failures gracefully
|
|
12
|
+
- [ ] Implement distributed locking for clusters
|
|
13
|
+
- [ ] Monitor job execution times
|