### Complete JobRunner Example Source: https://github.com/risevest/octonet/blob/master/docs/Jobs.md Demonstrates the setup and usage of JobRunner, including starting jobs, manually triggering one, and setting up a graceful shutdown. ```typescript import { Container } from "inversify"; import { Redis } from "ioredis"; import { Logger } from "octonet"; import { JobRunner } from "octonet/jobs/runner"; const container = new Container(); const redis = new Redis(process.env.REDIS_URL); const logger = new Logger({ name: "job-runner" }); const runner = new JobRunner(container); // Start all jobs await runner.start(redis, logger); // Manually trigger a job await runner.run("my-jobs.cleanup"); // Graceful shutdown process.on("SIGTERM", () => { runner.stop(); redis.quit(); }); ``` -------------------------------- ### Install Octonet dependencies Source: https://github.com/risevest/octonet/blob/master/README.md Use this command to add the library and required metadata reflection to your project. ```bash yarn install --save @risemaxi/octonet reflect-metadata ``` -------------------------------- ### Initialize and Start Octonet Job Runner Source: https://context7.com/risevest/octonet/llms.txt Sets up the InversifyJS container, binds services, initializes Redis and Logger, and starts the Octonet JobRunner. Demonstrates manual job triggering and stopping, and graceful shutdown. ```typescript async function startJobRunner() { const container = new Container(); container.bind("ReportService").to(ReportService); const redis = new Redis("redis://localhost:6379"); const logger = new Logger({ name: "job-runner", serializers: defaultSerializers() }); const runner = new JobRunner(container); await runner.start(redis, logger); console.log("Job runner started"); // Manually trigger a job runner.run("reports.daily-summary"); // Stop specific job runner.stop("maintenance.cache-cleanup"); // Graceful shutdown process.on("SIGTERM", () => { runner.stop(); redis.quit(); }); } ``` -------------------------------- ### JobRunner Start Method Source: https://github.com/risevest/octonet/blob/master/docs/Jobs.md Starts all scheduled jobs and processes any pending queue items. Requires Redis and Logger instances. ```typescript const runner = new JobRunner(container); await runner.start(redis, logger); ``` -------------------------------- ### Authorization Header Formats Source: https://github.com/risevest/octonet/blob/master/docs/Authentication.md Demonstrates the general format and specific examples of authorization headers for user and system sessions in Octonet. ```javascript // express request headers. // general format req.headers.authorization = `${scheme} ${token}`; // request header for a user session with a `Bearer` scheme req.headers.authorization = `Bearer ${token}`; // request header for a system session with a custom-defined scheme req.headers.authorization = `Custom ${token}`; ``` -------------------------------- ### Setup RabbitMQ Publisher and Queue Source: https://context7.com/risevest/octonet/llms.txt Connects to RabbitMQ, sets up a queue with a maximum item limit or TTL, and pushes messages. Ensure the connection URL and logger are correctly configured. Graceful shutdown is handled via SIGTERM. ```typescript async function setupPublisher() { const logger = new Logger({ name: "publisher", serializers: defaultSerializers() }); const factory = await QueueFactory.connect("amqp://localhost:5672", logger); // Create queue with max 1000 items const orderQueue = await factory.queue<{ orderId: string; items: any[] }>("ORDERS_PROCESS", 1000); // Or with TTL (messages expire after 1 hour) const tempQueue = await factory.queue("TEMP_QUEUE", "1h"); // Push messages orderQueue.push({ orderId: "order-123", items: [{ sku: "ABC", qty: 2 }] }); // Check connection health console.log("Connected:", factory.isConnected()); // Graceful shutdown process.on("SIGTERM", async () => { await factory.close(); }); } ``` -------------------------------- ### Make a GET Request with Octonet HTTP Agent Source: https://github.com/risevest/octonet/blob/master/docs/HTTP.md Use the `get` method of the http agent to initiate a GET request. Chain with `do` to execute and retrieve the response, optionally setting a timeout. ```typescript http.get("/users", { page: 1 }) .do(5000) .then(res => { // handle response }) .catch(err => { // handle error }) ``` -------------------------------- ### Basic Job Setup Source: https://github.com/risevest/octonet/blob/master/docs/Jobs.md Define a job group using the @cron decorator and initialize the JobRunner with a Redis connection and logger. ```typescript import { cron, daily, Logger } from "octonet"; import { Container } from "inversify"; import { Redis } from "ioredis"; import { JobRunner } from "octonet/jobs/runner"; // 1. Define a job group @cron("my-jobs") class MyJobs { @daily("cleanup") async cleanupJob() { console.log("Running daily cleanup"); // Your cleanup logic here } } // 2. Set up the runner const container = new Container(); const redis = new Redis("redis://localhost:6379"); const logger = new Logger({ name: "jobs" }); const runner = new JobRunner(container); await runner.start(redis, logger); ``` -------------------------------- ### Implement OpenTelemetry TracingProvider Source: https://github.com/risevest/octonet/blob/master/docs/Logging.md Example implementation of the TracingProvider interface for services using OpenTelemetry. ```ts import { trace } from "@opentelemetry/api"; import { TracingProvider } from "@risemaxi/octonet"; export const otelTracingProvider: TracingProvider = { getActiveTraceContext() { const span = trace.getActiveSpan(); if (!span) return null; const { traceId, spanId, traceFlags } = span.spanContext(); return { traceId, spanId, traceFlags }; } }; ``` -------------------------------- ### Start AMQP Workers Source: https://context7.com/risevest/octonet/llms.txt Initializes and starts the AMQP workers with a specified Inversify container, logger, and number of parallel consumers. The connection URL and logger configuration are essential. ```typescript async function startWorkers() { const container = new Container(); container.bind("OrderService").to(OrderService); const logger = new Logger({ name: "order-workers", serializers: defaultSerializers() }); const workers = new Workers(container); await workers.start("amqp://localhost:5672", logger, 5); // 5 parallel consumers console.log("AMQP workers started"); console.log("Running:", workers.isRunning()); } ``` -------------------------------- ### Log Output with Tracing Source: https://github.com/risevest/octonet/blob/master/docs/Logging.md Example of a JSON log entry enriched with trace and span IDs. ```json { "name": "rise-analytics", "msg": "successfully connected to redis", "trace_id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4", "span_id": "1a2b3c4d5e6f7a8b", "level": 30, "time": "2026-02-26T12:00:00.000Z" } ``` -------------------------------- ### NATS Consumer Setup and Subscription Source: https://context7.com/risevest/octonet/llms.txt Sets up a NATS consumer with dependency injection and subscribes to JetStream subjects using decorators. Requires NATS connection and a container for services. ```typescript import { Logger, Consumers, NatsPublisher, stream, subscribe, defaultSerializers } from "@risemaxi/octonet"; import { Container, inject, injectable } from "inversify"; import { connect, NatsConnection } from "nats"; // Define service interface interface INotificationService { sendEmail(to: string, subject: string, body: string): Promise; sendSMS(to: string, message: string): Promise; } // Implementation @injectable() class NotificationService implements INotificationService { async sendEmail(to: string, subject: string, body: string): Promise { console.log(`Sending email to ${to}: ${subject}`); } async sendSMS(to: string, message: string): Promise { console.log(`Sending SMS to ${to}: ${message}`); } } // Middleware functions function validatePayload(data: any) { if (!data || !data.userId) { throw new Error("Invalid payload: missing userId"); } return data; } function enrichWithTimestamp(data: any) { return { ...data, processedAt: new Date() }; } // Stream class with subscribers @stream("notifications", validatePayload) class NotificationHandlers { @inject("NotificationService") private notificationService: INotificationService; // Listens on subject: notifications.email @subscribe("email", enrichWithTimestamp) async handleEmailNotification(data: { userId: string; email: string; subject: string; body: string }) { await this.notificationService.sendEmail(data.email, data.subject, data.body); } // Listens on subject: notifications.sms @subscribe("sms") async handleSMSNotification(data: { userId: string; phone: string; message: string }) { await this.notificationService.sendSMS(data.phone, data.message); } } // Setup and start consumer async function startConsumer() { const container = new Container(); container.bind("NotificationService").to(NotificationService); const logger = new Logger({ name: "notification-consumer", serializers: defaultSerializers() }); const natsConnection: NatsConnection = await connect({ servers: "nats://localhost:4222" }); const consumer = new Consumers(container); await consumer.start(natsConnection, logger, { namespace: "production", batch_size: 10, timeout: "30s" }); console.log("NATS consumer started"); } ``` -------------------------------- ### Standalone RedisQueue Example Source: https://github.com/risevest/octonet/blob/master/docs/Jobs.md Demonstrates using RedisQueue independently for producing and consuming jobs, specifying retry and timeout parameters. ```typescript import { RedisQueue } from "octonet/jobs/queue"; import { Redis } from "ioredis"; const redis = new Redis(); const queue = new RedisQueue("orders", redis, 3, "10s"); // Producer await queue.fill(await getOrders()); // Consumer await queue.work( async order => { await processOrder(order); }, logger, 10 ); ``` -------------------------------- ### Job Decorator Examples Source: https://github.com/risevest/octonet/blob/master/docs/Jobs.md Illustrates how to use the @job decorator to configure and schedule jobs with different retry and timeout settings. ```typescript // High-priority job with aggressive retries @job('critical-sync', '*/5 * * * *', { retries: 5, timeout: '5s', maxComputeTime: '10m' }) // Long-running job with no retries @job('heavy-computation', '0 2 * * *', { retries: 0, maxComputeTime: '4h' }) ``` -------------------------------- ### JobRunner API Source: https://github.com/risevest/octonet/blob/master/docs/Jobs.md The JobRunner class manages the lifecycle of scheduled jobs, allowing for starting, stopping, and manual triggering of tasks. ```APIDOC ## JobRunner ### Description Manages job lifecycle and execution within the Octonet system. ### Constructor `new JobRunner(container: Container)` ### Methods - **start(redis: Redis, logger: Logger)**: Starts all scheduled jobs and processes pending queue items. - **run(job: string)**: Manually triggers a specific job by name. - **stop(job?: string)**: Stops scheduled tasks. If a job name is provided, only that job is stopped; otherwise, all jobs are stopped. ``` -------------------------------- ### Complex Cron Scheduling Source: https://github.com/risevest/octonet/blob/master/docs/Jobs.md Utilize full cron syntax for custom job schedules. Examples include scheduling jobs for specific times during business hours or on particular days of the month. ```typescript // Every 15 minutes during business hours (9 AM - 5 PM) on weekdays @job('sync', '*/15 9-17 * * 1-5') async syncData() { // ... } // At 2:30 AM on the 1st and 15th of each month @job('semi-monthly', '30 2 1,15 * *') async semiMonthlyReport() { // ... } ``` -------------------------------- ### Initialize and use RedisStore Source: https://github.com/risevest/octonet/blob/master/docs/Authentication.md Demonstrates creating a RedisStore instance and performing lifecycle operations like commissioning, peeking, extending, resetting, decommissioning, and revoking sessions. ```typescript // redis.store.ts import { RedisStore } from "@risemaxi/octonet"; import Redis from "./redis.config"; const SECRET = "my_secret"; // use the secret specified in your .env file const key = "user@example.com"; // unique key // sample session object const session = { id: 1, email: "user@example.com", role: "user" }; const redisStore: RedisStore = new RedisStore(SECRET, Redis); // sample immediately invoking start function for the purpose of this example (async function () { // create a token with an expiry time of 1 hour const token: string = await redisStore.commission(key, session, "1h"); // returns a cryptographic token // view the object referenced by the token (in this case, it's the session object created above) const storedSession = await redisStore.peek(token); // reset the expiry time for the token to 30 mins await redisStore.extend(token, "30m"); // reset the object referenced by the token const newSession = { id: 1, email: "anotherUser@example.com", role: "user" }; /* reset the token. * after this function has been called, redisStore.peek(token) === newSession */ await redisStore.reset(key, newSession); /* decommission a token * after this function has been called, redisStore.peek(token) === null */ await redisStore.decommission(token); /* revoke a token * after this function has been called, redisStore.peek(token) === null */ await redisStore.revoke(key); })(); ``` -------------------------------- ### Create NatsConsumer and Publisher Instance Source: https://github.com/risevest/octonet/blob/master/docs/Consumer.md Sets up a `NatsConsumer` and `NatsPublisher` for handling wallet events. It initializes the consumer, connects to NATS, and publishes test messages. ```typescript // index.ts import { Logger, NatsConsumer, NatsPublisher, publisherFactory, defaultSerializers } from "@risemaxi/octonet"; import "./wallet.ts"; // needed for initialization of the Wallet event class import { container } from "./invesify.config"; import { createQueue, Queue } from "./amqp.helper"; // NATS URL const natsUrl = "demo.nats.io:4443"; let consumer: NatsConsumer; let logger: Logger; let publisher: NatsPublisher; // create a Logger instance const logger = new Logger({ name: "wallet_demo", serializers: defaultSerializers(), verbose: false }); // immediately invoking function (async function () { consumer = new Consumer(container, logger); const natsConnection = await connect(natsUrl); consumer.listen(nats, { namespace: "wallets-namespace", batch_size: 10, timeout: "1m" }); publisher = await publisherFactory(natsConnection); // testing the `WALLET` class await publisher.publish("wallet.func", 200); await publisher.publish("wallet.withdraw", 100); })(); ``` -------------------------------- ### General and Contextual Logging Source: https://context7.com/risevest/octonet/llms.txt Demonstrates basic logging, logging with context objects, and error logging. Also shows how to create child loggers for specific modules. ```typescript // General logging logger.log("Service started successfully"); logger.log("Processing order", { orderId: "12345", amount: 99.99 }); // Error logging try { throw new Error("Payment processing failed"); } catch (error) { logger.error(error as Error, { orderId: "12345", paymentMethod: "card" }); logger.error(error as Error, "Failed to process payment"); } // Child logger for specific contexts const paymentLogger = logger.child({ module: "payments" }); paymentLogger.log("Payment initiated", { amount: 100 }); ``` -------------------------------- ### Create Redis Client Source: https://github.com/risevest/octonet/blob/master/docs/Authentication.md Sets up an IORedis client instance for connecting to a Redis server. Ensure the Redis URL is configured, typically via environment variables. ```typescript // redis.config.ts import IORedis from "ioredis"; import Logger from "./logger"; const redis_url = "redis://localhost:6379"; // read this from your .env file const Redis = new IORedis(redis_url); Redis.on("error", err => { Logger.error(err, "An error occured with the Redis client."); }); export default Redis; ``` -------------------------------- ### Initialize and use Logger module Source: https://github.com/risevest/octonet/blob/master/docs/Logging.md Demonstrates creating a Logger instance with custom serializers and using utility functions for Express requests, responses, and errors. ```js import express from "express"; import { Logger, defaultSerializers } from "@risemaxi/octonet"; // create the Logger instance const logger: Logger = new Logger({ name: "wallet_demo", serializers: defaultSerializers("password"), verbose: false }); // Express-related Logger utility functions app.get("/test", (err, req, res) => { logger.request(req); logger.response(res); logger.httpError(err, req, res); }); // axios-related utility functions // others logger.log("transactionn service called"); logger.error("an internal server error has occured"); ``` -------------------------------- ### RedisStore Usage Source: https://github.com/risevest/octonet/blob/master/docs/Authentication.md Demonstrates the creation and usage of Octonet's RedisStore instance for managing sessions with Redis. ```APIDOC ## RedisStore Operations ### Description This section details the operations available for the `RedisStore` class, which is used for managing session data with Redis. ### Method `RedisStore` is a class that requires instantiation. ### Endpoint N/A (Client-side implementation) ### Parameters #### Constructor Parameters - **secret** (string) - Required - The secret key used for cryptographic operations. - **redisClient** (Redis) - Required - An instance of the Redis client. ### Methods #### `commission(key: string, session: any, expiry: string)` - **Description**: Creates a new token associated with the provided key and session data, with a specified expiry time. - **Parameters**: - `key` (string) - Required - A unique key to identify the session. - `session` (any) - Required - The session data to be stored. - `expiry` (string) - Required - The expiry time for the token (e.g., "1h", "30m"). - **Returns**: A cryptographic token (string). #### `peek(token: string)` - **Description**: Retrieves the session data associated with a given token without affecting its expiry. - **Parameters**: - `token` (string) - Required - The token to retrieve data for. - **Returns**: The stored session data (any) or null if the token is invalid or expired. #### `extend(token: string, expiry: string)` - **Description**: Resets the expiry time for an existing token. - **Parameters**: - `token` (string) - Required - The token to extend. - `expiry` (string) - Required - The new expiry time (e.g., "1h", "30m"). - **Returns**: Promise #### `reset(key: string, session: any)` - **Description**: Resets the session data associated with a given key. - **Parameters**: - `key` (string) - Required - The key of the session to reset. - `session` (any) - Required - The new session data. - **Returns**: Promise #### `decommission(token: string)` - **Description**: Removes the token and its associated session data. - **Parameters**: - `token` (string) - Required - The token to decommission. - **Returns**: Promise #### `revoke(key: string)` - **Description**: Revokes all tokens associated with a given key. - **Parameters**: - `key` (string) - Required - The key whose tokens should be revoked. - **Returns**: Promise ### Request Example ```js import { RedisStore } from "@risemaxi/octonet"; import Redis from "./redis.config"; const SECRET = "my_secret"; const key = "user@example.com"; const session = { id: 1, email: "user@example.com", role: "user" }; const redisStore = new RedisStore(SECRET, Redis); // Create a token with 1 hour expiry const token = await redisStore.commission(key, session, "1h"); // View stored session const storedSession = await redisStore.peek(token); // Extend token expiry to 30 minutes await redisStore.extend(token, "30m"); // Reset session data const newSession = { id: 1, email: "anotherUser@example.com", role: "user" }; await redisStore.reset(key, newSession); // Decommission a token await redisStore.decommission(token); // Revoke all tokens for a key await redisStore.revoke(key); ``` ``` -------------------------------- ### Initialize AMQP Consumer Instance Source: https://github.com/risevest/octonet/blob/master/docs/AMQP.md Sets up the ConnectionManager and AMQPWorker to listen for messages on configured queues. Requires an active RabbitMQ connection and the registration of event classes. ```typescript // index.ts import { Logger, ConnectionManager, AMQPQueue, AMQPWorker, defaultSerializers } from "@risemaxi/octonet"; import "./wallet.ts"; // needed for initialization of the Wallet event class import { container } from "./invesify.config"; import { createQueue, Queue } from "./amqp.helper"; // RABBITMQ CONNECTION const amqpURL = "amqp://localhost:5672"; let manager: ConnectionManager; let logger: Logger; let queue: AMQPQueue; let worker: AMQPWorker; // create a Logger instance const logger = new Logger({ name: "wallet_demo", serializers: defaultSerializers(), verbose: false }); // immediately invoking function (async function () { manager = new ConnectionManager(logger); worker = new AMQPWorker(container, logger); await manager.connect("namespace", amqpUrl); const channel = await manager.createChannel("namespace"); worker.listen(channel); queue = new AMQPQueue(channel); // testing the `WALLET` class by pushing data(messages) to the various queues await queue.push("WALLET_FUND", 200); await queue.push("WALLET_WITHDRAW", 100); })(); ``` -------------------------------- ### Configure Inversify Container Source: https://github.com/risevest/octonet/blob/master/docs/Consumer.md Sets up dependency injection bindings for the wallet repository. ```typescript // inversify.config.ts import { Container } from "inversify"; import { IFundWallet} from "./wallet.interface"; import { FundWallet } from "./wallet.repo"; export const WALLET_TAG = Symbol.for('Wallet'); const container = new Container(); container.bind(WALLET_TYPE).to(FundWallet); export container; ``` -------------------------------- ### Http Agent Methods Source: https://github.com/risevest/octonet/blob/master/docs/HTTP.md The http agent is used for making external API requests. It provides methods for setting a logger, making different types of HTTP requests (GET, POST, PUT, PATCH, DELETE), and chaining methods to modify and execute requests. ```APIDOC ## Http Agent The http agent is used for making external API requests and has the following methods: ### Methods - **useLogger(logger: _Logger_)**: Sets the logger to be used for logging requests. ### Request Methods - **get(url: _string_, params?: _object_)**: _RequestWrapper_ - **post(url: _string_, body?: _object_)**: _RequestWrapper_ - **put(url: _string_, body?: _object_)**: _RequestWrapper_ - **patch(url: _string_, body?: _object_)**: _RequestWrapper_ - **del(url: _string_, params?: _object_)**: _RequestWrapper_ These methods return a **RequestWrapper** object which can be chained with the following methods: ### Request Wrapper Chaining Methods - **do(timeout?: _number_)**: Executes the request and returns the response. Takes an optional timeout parameter. - **track(req?: _Request_)**: Checks for or sets a request ID. - **set(key: _string_, val: _string_)**: Sets a request header. - **auth(req?: _Request_)**: Checks for or adds an authorization token. - **type(t: _"json" | "form" | "urlencoded"_)**: Sets the request Content-Type. ``` -------------------------------- ### Implement Wallet Repository Source: https://github.com/risevest/octonet/blob/master/docs/Consumer.md Provides the concrete implementation for the wallet interface. ```typescript // wallet.repo.ts import { IFundWallet } from "./wallet.interface"; export FundWallet implements IWallet{ fund(amount: number){ console.log(`Your wallet has been funded with $${amount}!`); } wallet(amount: number){ console.log(`$${amount} was just withdrawn from your wallet!`); } } ``` -------------------------------- ### Configure and Use HttpAgent for Microservice Communication Source: https://context7.com/risevest/octonet/llms.txt Configure HttpAgent with service details, authentication, and logging. Use its fluent API for making HTTP requests with automatic authentication, tracing, and error handling. Supports various request types and timeouts. ```typescript import { AgentConfig, HttpAgent, Logger, defaultSerializers, APIError, TimeoutError, HttpError, NoRequestIDError, NoAuthorizationTokenError } from "@risemaxi/octonet"; // Configure the HTTP agent const config: AgentConfig = { service: "user-service", scheme: "RiseAuth", secret: "your-32-character-secret-key-here", timeout: "10s", logger: new Logger({ name: "user-service", serializers: defaultSerializers("password", "token") }) }; const http = new HttpAgent(config); // Make a POST request with authentication and tracking async function createUser(req: Express.Request) { const userData = { email: "user@example.com", name: "John Doe" }; try { const response = await http .post("https://api.internal/users", userData) .set("Authorization", req.headers.authorization) .track(req) // Propagates X-Request-ID for distributed tracing .type("json") .do(30); // 30 second timeout return response; } catch (error) { if (error instanceof APIError) { console.error(`API Error: ${error.status} - ${JSON.stringify(error.data)}`); } else if (error instanceof TimeoutError) { console.error("Request timed out"); } else if (error instanceof HttpError) { console.error(`HTTP Error: ${error.axios_code}`); } throw error; } } // System-to-system request with auto-generated JWT token async function systemRequest() { const response = await http .get("https://api.internal/health") .auth() // Auto-generates JWT with service credentials .track() // Auto-generates X-Request-ID .do(); return response; } // Form data upload async function uploadFile(fileData: object) { const response = await http .post("https://api.internal/upload", fileData) .type("form") .auth() .do(60); return response; } ``` -------------------------------- ### Initialize Logger with Tracing Source: https://context7.com/risevest/octonet/llms.txt Sets up a structured logger with optional distributed tracing integration using OpenTelemetry. Sensitive fields can be redacted during serialization. ```typescript import { Logger, defaultSerializers, TracingProvider, TraceContext } from "@risemaxi/octonet"; import { trace } from "@opentelemetry/api"; import express from "express"; // OpenTelemetry tracing provider implementation const otelTracingProvider: TracingProvider = { getActiveTraceContext(): TraceContext | null { const span = trace.getActiveSpan(); if (!span) return null; const { traceId, spanId, traceFlags } = span.spanContext(); return { traceId, spanId, traceFlags }; } }; // Create logger with tracing and sensitive field redaction const logger = new Logger({ name: "order-service", serializers: defaultSerializers("password", "creditCard", "ssn"), verbose: true, // Set to false in production to only log errors tracing: otelTracingProvider }); ``` -------------------------------- ### Wallet Repository Implementation Source: https://github.com/risevest/octonet/blob/master/docs/AMQP.md Implements the IFundWallet interface to provide the core logic for wallet funding and withdrawal. This implementation is bound to the interface using Inversify. ```typescript import { IFundWallet } from "./wallet.interface"; export FundWallet implements IWallet{ fund(amount: number){ console.log(`Your wallet has been funded with $${amount}!`); } wallet(amount: number){ console.log(`$${amount} was just withdrawn from your wallet!`); } } ``` -------------------------------- ### Distributed Tracing Configuration Source: https://github.com/risevest/octonet/blob/master/docs/Logging.md How to configure and enable distributed tracing using the TracingProvider interface. ```APIDOC ## Distributed Tracing ### Enabling Tracing Pass a `TracingProvider` to the Logger configuration to enable automatic enrichment of log entries with `trace_id` and `span_id`. ### TracingProvider Interface ```ts interface TraceContext { traceId: string; spanId: string; traceFlags?: number; } interface TracingProvider { getActiveTraceContext(): TraceContext | null; } ``` ### Implementation Example ```ts const logger = new Logger({ name: "service-name", tracing: myTracingProvider }); ``` ``` -------------------------------- ### Make a POST Request with Octonet HTTP Agent Source: https://github.com/risevest/octonet/blob/master/docs/HTTP.md Use the `post` method to send data via POST. Chain with `type` to set the content type and `do` to execute the request. ```typescript http.post("/users", { name: "John Doe" }) .type("json") .do() .then(res => { // handle response }) .catch(err => { // handle error }) ``` -------------------------------- ### Choosing Appropriate maxComputeTime Source: https://github.com/risevest/octonet/blob/master/docs/Jobs.md Set `maxComputeTime` to a realistic duration for your job to prevent lock contention. Short jobs require less time, while long jobs need sufficient allocation. ```typescript // Short job - 10 minutes is plenty @job('quick-sync', '*/5 * * * *', { maxComputeTime: '10m' }) // Long job - give it enough time @job('data-migration', '0 2 * * *', { maxComputeTime: '4h' }) ``` -------------------------------- ### Define Subscription Jobs with Query and Cron Schedules Source: https://context7.com/risevest/octonet/llms.txt Implements jobs for subscription management, using a query to fetch data for batch processing and a cron job to send renewal reminders. Configurable with retries and timeouts. ```typescript @cron("subscriptions") class SubscriptionJobs { @inject("ReportService") private reportService: IReportService; // Query generates list of items to process @query("renewal-reminders") async getExpiredSubscriptions() { return await this.reportService.getExpiredSubscriptions(); } // Job processes each item from the query (runs daily at 9 AM) @job("renewal-reminders", "0 9 * * *", { retries: 2, timeout: "10s" }) async sendRenewalReminder(user: { userId: string; email: string }) { await this.reportService.sendRenewalReminder(user); } } ``` -------------------------------- ### Job Scheduling Decorators Source: https://github.com/risevest/octonet/blob/master/docs/Jobs.md Documentation for the core decorators used to define job groups, query generators, and scheduled job handlers. ```APIDOC ## @cron(name: string) ### Description Marks a class as a job group, making it injectable and registering it within the system. ### Parameters - **name** (string) - Required - Unique identifier for the job group. ## @job(name: string, schedule: string, config?: JobConfig) ### Description Marks a method as a job handler that executes on a specific cron schedule. ### Parameters - **name** (string) - Required - Job identifier (must match query name if using query-job pairing). - **schedule** (string) - Required - Cron expression (e.g., '0 0 * * *'). - **config** (JobConfig) - Optional - Configuration object for retries, timeouts, and compute limits. ## @query(name: string) ### Description Marks a method as a data generator for a job. The returned list is processed by the corresponding @job handler. ### Parameters - **name** (string) - Required - Must match the name of the corresponding @job. ``` -------------------------------- ### Wallet Event Class with AMQP Decorators Source: https://github.com/risevest/octonet/blob/master/docs/AMQP.md Defines the Wallet event class, decorated with @jobs to group events and @command to subscribe to specific queues for handling funding and withdrawal events. It uses dependency injection for the wallet repository. ```typescript import { job, command } from "@risemaxi/octonet"; import { WALLET_TAG, container } from "./inversify.config"; import { IFundWallet} from "./wallet.interface"; @jobs('wallet') export class Wallet { @inject(WALLET_TAG) private walletRepo: IFundWallet; //listens on queue = WALLET_FUND @command('wallet.fund') executeWalletFunding(amount: number): void { this.walletRepo.fund(amount); } //listens on queue = WALLET_WITHDRAW @command('wallet.withdraw') eexecuteWalletWithdrawal(amount): void { this.walletRepo.withdraw(amount); } } ``` -------------------------------- ### Initialize Logger with OpenTelemetry Source: https://github.com/risevest/octonet/blob/master/docs/Logging.md Pass the OpenTelemetry provider instance to the Logger constructor. ```ts const logger = new Logger({ name: env.service_name, serializers: defaultSerializers(), tracing: otelTracingProvider }); ``` -------------------------------- ### Create Wallet Event Class Source: https://github.com/risevest/octonet/blob/master/docs/Consumer.md Uses @stream and @subscribe decorators to handle NATS events via dependency injection. ```typescript // wallet.ts import { stream, subscribe } from "@risemaxi/octonet"; import { WALLET_TAG, container } from "./inversify.config"; import { IFundWallet} from "./wallet.interface"; @stream('wallet') export class Wallet { @inject(WALLET_TAG) private walletRepo: IFundWallet; //listens on subject = wallet.fund @subscribe('fund') executeWalletFunding(amount: number): void { this.walletRepo.fund(amount); } //listens on subject = wallet.withdraw @subscribe('withdraw') eexecuteWalletWithdrawal(amount): void { this.walletRepo.withdraw(amount); } } ``` -------------------------------- ### Create and Use RedisQueue for Email Jobs Source: https://context7.com/risevest/octonet/llms.txt Demonstrates creating a RedisQueue for email jobs with retry and timeout configurations. Use this for serial job processing with fault tolerance. ```typescript import { RedisQueue, Logger, defaultSerializers } from "@risemaxi/octonet"; import { Redis } from "ioredis"; const redis = new Redis("redis://localhost:6379"); const logger = new Logger({ name: "queue-processor", serializers: defaultSerializers() }); interface EmailJob { to: string; subject: string; body: string; priority: "high" | "normal" | "low"; } // Create queue with 3 retries and 10s timeout between retries const emailQueue = new RedisQueue("email-jobs", redis, 3, "10s"); // Producer: Fill the queue with jobs async function enqueueEmails(emails: EmailJob[]) { const added = await emailQueue.fill(emails); if (added) { console.log(`Added ${emails.length} emails to queue`); } else { console.log("Queue already has pending items"); } } // Producer: Fill with async generator for large datasets async function* generateEmails(): AsyncGenerator { let offset = 0; const batchSize = 100; while (true) { const users = await fetchUsersFromDB(offset, batchSize); if (users.length === 0) break; yield users.map(user => ({ to: user.email, subject: "Newsletter", body: "Your weekly update", priority: "normal" as const })); offset += batchSize; } } async function enqueueLargeDataset() { await emailQueue.fill(generateEmails()); } // Consumer: Process jobs with parallel workers async function processEmails() { await emailQueue.work( async (job: EmailJob) => { console.log(`Sending email to ${job.to}`); await sendEmail(job.to, job.subject, job.body); }, logger, 5 // 5 parallel workers ); } // Check queue status async function checkQueueStatus() { const pending = await emailQueue.length(); console.log(`Pending jobs: ${pending}`); } // Requeue failed jobs from dead-letter queue async function requeueFailedJobs() { const hadFailures = await emailQueue.requeue(); if (hadFailures) { console.log("Re-queued failed jobs for retry"); } } // Helper functions (mock implementations) async function fetchUsersFromDB(offset: number, limit: number) { return []; } async function sendEmail(to: string, subject: string, body: string) { // Email sending logic } ``` -------------------------------- ### Upgrade Octonet version Source: https://github.com/risevest/octonet/blob/master/README.md Commands for updating the library to a specific version or the latest release. ```bash yarn upgrade @risemaxi/octonet@version ``` ```bash yarn upgrade @risemaxi/octonet --latest ``` -------------------------------- ### Manage system sessions with JWT Source: https://github.com/risevest/octonet/blob/master/docs/Authentication.md Shows how to encode and decode JSON Web Tokens for system session management using a 32-character secret. ```javascript import { jwt } from "@risemaxi/octonet"; const mySecret = "12345678123456781234567812345678"; //32 character string const payload = { email: "email@rise.com", username: "risemaxi" }; const encodedSecret: Uint8Array = new TextEncoder().encode(mySecret); (async () => { const token = await jwt.encode(encodedSecret, "1h", payload); console.log(token); //logs jwt token const data = await jwt.decode(encodedSecret, token); console.log(data); //should be equal to payload })(); ``` -------------------------------- ### Convenience Schedule Decorators Source: https://github.com/risevest/octonet/blob/master/docs/Jobs.md Use pre-configured decorators for common scheduling intervals. ```typescript @hourly('sync-data') async syncData() { // Runs at 00:00, 01:00, 02:00, etc. } ``` ```typescript @daily('cleanup') async cleanup() { // Runs at 00:00 every day } ``` ```typescript @weekly('reports') async generateWeeklyReport() { // Runs at 00:00 every Sunday } ``` ```typescript @monthly('billing') async processBilling() { // Runs at 00:00 on the 1st of each month } ``` -------------------------------- ### RedisStore Authentication Utilities Source: https://github.com/risevest/octonet/blob/master/docs/Authentication.md Utility functions for managing session tokens in the Redis store. ```APIDOC ## RedisStore Utility Functions ### commission(key, val, time) - **Description**: Creates a cryptographic token and saves the session data in Redis. - **Parameters**: - **key** (string) - Required - Unique key for token generation. - **val** (any) - Required - Session object to be referenced. - **time** (string) - Required - Expiry time (e.g., '1h', '30m'). - **Returns**: Promise (The created token). ### peek(token) - **Description**: Retrieves the session object from Redis without modifying token validity. - **Parameters**: - **token** (string) - Required - The cryptographic token. - **Returns**: AsyncNullable (Session object or null). ### extend(token, time) - **Description**: Resets the expiry time of a specified token. - **Parameters**: - **token** (string) - Required - The reference token. - **time** (string) - Required - New expiry time. - **Returns**: AsyncNullable (Session object or null). ### reset(key, newVal) - **Description**: Replaces the content a token points to. - **Parameters**: - **key** (string) - Required - The unique key used for creation. - **newVal** (any) - Required - The new content. ### decommission(token) - **Description**: Deletes a token from Redis and returns the referenced content. - **Parameters**: - **token** (string) - Required - The token to delete. - **Returns**: AsyncNullable (Referenced content or null). ### revoke(key) - **Description**: Deletes a token and its referenced content from Redis. - **Parameters**: - **key** (string) - Required - The unique key used for creation. ``` -------------------------------- ### RedisQueue Constructor Source: https://github.com/risevest/octonet/blob/master/docs/Jobs.md Initializes a RedisQueue with a name, Redis instance, and optional retry/timeout configurations. Default retries are 3 and timeout is '10s'. ```typescript new RedisQueue( name: string, redis: Redis, retries?: number, timeout?: string ) ``` -------------------------------- ### Convenience Scheduling Decorators Source: https://github.com/risevest/octonet/blob/master/docs/Jobs.md Pre-configured decorators for common cron schedules. ```APIDOC ## Convenience Decorators ### @hourly(name: string, config?: JobConfig) Runs every hour at minute 0. ### @daily(name: string, config?: JobConfig) Runs daily at midnight. ### @weekly(name: string, config?: JobConfig) Runs weekly on Sunday at midnight. ### @monthly(name: string, config?: JobConfig) Runs monthly on the 1st at midnight. ``` -------------------------------- ### Define Report Service Interface and Implementation Source: https://context7.com/risevest/octonet/llms.txt Defines the contract for report generation and subscription management services. The implementation provides mock data for demonstration. ```typescript interface IReportService { generateDailyReport(): Promise; getExpiredSubscriptions(): Promise<{ userId: string; email: string }[]>; sendRenewalReminder(user: { userId: string; email: string }): Promise; } @injectable() class ReportService implements IReportService { async generateDailyReport(): Promise { console.log("Generating daily report..."); } async getExpiredSubscriptions(): Promise<{ userId: string; email: string }[]> { return [ { userId: "user1", email: "user1@example.com" }, { userId: "user2", email: "user2@example.com" } ]; } async sendRenewalReminder(user: { userId: string; email: string }): Promise { console.log(`Sending renewal reminder to ${user.email}`); } } ``` -------------------------------- ### Implement Graceful Shutdown Source: https://github.com/risevest/octonet/blob/master/docs/Jobs.md Ensure clean resource release and job termination by listening for system signals. ```typescript const cleanup = async () => { runner.stop(); // Stop scheduling new jobs await redis.quit(); // Close Redis connection process.exit(0); }; process.on("SIGTERM", cleanup); process.on("SIGINT", cleanup); ``` -------------------------------- ### Inversify Configuration for Wallet Binding Source: https://github.com/risevest/octonet/blob/master/docs/AMQP.md Sets up the InversifyJS container to bind the IFundWallet interface to its concrete implementation, FundWallet. It also imports the wallet class to ensure its decorators are registered. ```typescript import { Container } from "inversify"; import { IFundWallet} from "./wallet.interface"; import { FundWallet } from "./wallet.repo"; import './wallet.ts' export const WALLET_TAG = Symbol.for('Wallet'); const container = new Container(); container.bind(WALLET_TYPE).to(FundWallet); export container; ``` -------------------------------- ### AMQP Decorators Source: https://github.com/risevest/octonet/blob/master/docs/AMQP.md Decorators used to define event groups and command handlers within the Octonet framework. ```APIDOC ## Decorators ### @jobs(name: string, ...groupMiddleware) - **Description**: Annotated at the top of an event class to define an event group. ### @command(queue: string, ...middleware) - **Description**: Annotated at the top of a handler function within an event class. It executes when the specified event is dispatched. - **Note**: The queue string is automatically transformed (capitalized, '.' replaced with '_'). Example: 'wallet.fund' becomes 'WALLET_FUND'. ``` -------------------------------- ### Making HTTP Requests and Handling Errors with Octonet Source: https://github.com/risevest/octonet/blob/master/docs/HTTP.md Use this snippet to make POST requests and handle potential errors. Ensure necessary environment variables and logger configurations are set up. ```typescript import { AgentConfig, HttpAgent, Logger } from "@risemaxi/octonet"; const env = process.env; const logger = new Logger({ name: env.service_name, serializers: defaultSerializers() }); const HTTPAgentConfig: AgentConfig = { service: env.service_name, scheme: env.auth_scheme, secret: env.service_secret, logger: logger }; const http = new HttpAgent(HTTPAgentConfig)( // immediately invoking function async function () { let url = env.URL; let token = "Rise Token"; let data = { email: "email@rise.com", password: "password223" }; try { const response = await http.post(url, data).set("Authorization", token).track().do(); console.log(response); } catch (error) { if (error instanceof NoRequestIDError) { //this happens when .track is called with an a request argument that has no 'x-request-id' in the headers console.log("Request headers has does not have required field x-request-id"); } else if (error instanceof NoAuthorizationTokenError) { //this happens when .auth is called with a request argument that has no authorization field in the headers. console.log("Request headers has does not have required field authorization"); } else if (error instanceof TimeoutError) { //this happens when timeout of the request is exceeded console.log("Request timed out"); } else if (error instanceof APIError) { //this happens when a defined error and status code console.log(`request failed with status ${error.status} with data ${error.data}`); } else if (error instanceof HttpError) { //When an error occurs that doesnt fit into any of the above scenarios then it is treated an ah http error console.log("Sonething went wrong, but we don't know what it is."); console.log(error.rawError); } console.log(error.messsage); } } ); ```