Skip to content

Commit 19d654f

Browse files
authored
Merge pull request #139 from devtron-labs/release-candidate-v0.37.0
chore: merge rc-v0.37.0
2 parents 2fc2b5a + 220077b commit 19d654f

19 files changed

+1422
-376
lines changed

examples/getCommitsExample.ts

Lines changed: 0 additions & 91 deletions
This file was deleted.

src/app.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2024. Devtron Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import express from 'express';
18+
import bodyParser from 'body-parser';
19+
import { createRouter } from './routes';
20+
import { metricsMiddleware } from './middleware/metrics';
21+
import { NotificationService } from './notification/service/notificationService';
22+
23+
export const createApp = (notificationService: NotificationService) => {
24+
const app = express();
25+
26+
// Middleware
27+
app.use(bodyParser.json({ limit: '10mb' }));
28+
app.use(express.json());
29+
app.use(metricsMiddleware);
30+
31+
// Routes
32+
app.use(createRouter(notificationService));
33+
34+
return app;
35+
};

src/config/database.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright (c) 2024. Devtron Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { ConnectionOptions, createConnection } from "typeorm";
18+
import { NotificationSettings } from "../entities/notificationSettings";
19+
import { NotifierEventLog } from "../entities/notifierEventLogs";
20+
import { Event } from "../notification/service/notificationService";
21+
import { NotificationTemplates } from "../entities/notificationTemplates";
22+
import { SlackConfig } from "../entities/slackConfig";
23+
import { SesConfig } from "../entities/sesConfig";
24+
import { SMTPConfig } from "../entities/smtpConfig";
25+
import { WebhookConfig } from "../entities/webhookconfig";
26+
import { Users } from "../entities/users";
27+
import { logger } from "./logger";
28+
import * as process from "process";
29+
30+
export const connectToDatabase = async () => {
31+
const dbHost: string = process.env.DB_HOST;
32+
const dbPort: number = +process.env.DB_PORT;
33+
const user: string = process.env.DB_USER;
34+
const pwd: string = process.env.DB_PWD;
35+
const db: string = process.env.DB;
36+
37+
const dbOptions: ConnectionOptions = {
38+
type: "postgres",
39+
host: dbHost,
40+
port: dbPort,
41+
username: user,
42+
password: pwd,
43+
database: db,
44+
entities: [
45+
NotificationSettings,
46+
NotifierEventLog,
47+
Event,
48+
NotificationTemplates,
49+
SlackConfig,
50+
SesConfig,
51+
SMTPConfig,
52+
WebhookConfig,
53+
Users
54+
]
55+
};
56+
57+
try {
58+
const connection = await createConnection(dbOptions);
59+
logger.info("Connected to DB");
60+
return connection;
61+
} catch (error) {
62+
logger.error("TypeORM connection error: ", error);
63+
logger.error("shutting down notifier due to un-successful database connection...");
64+
process.exit(1);
65+
}
66+
};

src/config/logger.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) 2024. Devtron Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import * as winston from 'winston';
18+
19+
export const logger = winston.createLogger({
20+
level: 'info',
21+
format: winston.format.combine(
22+
winston.format.timestamp(),
23+
winston.format.printf(info => {
24+
return `${info.timestamp} ${info.level}: ${info.message}`;
25+
})
26+
),
27+
transports: [new winston.transports.Console()]
28+
});

src/config/nats.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (c) 2024. Devtron Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { connect, NatsConnection } from "nats";
18+
import { logger } from "./logger";
19+
import { PubSubServiceImpl } from "../pubSub/pubSub";
20+
import { NOTIFICATION_EVENT_TOPIC } from "../pubSub/utils";
21+
import { Event } from "../notification/service/notificationService";
22+
import { NotificationService } from "../notification/service/notificationService";
23+
import { successNotificationMetricsCounter, failedNotificationMetricsCounter } from '../common/metrics';
24+
25+
export const natsEventHandler = (notificationService: NotificationService) => async (msg: string) => {
26+
const eventAsString = JSON.parse(msg);
27+
const parsedData = JSON.parse(eventAsString);
28+
let response;
29+
30+
try {
31+
// First try to parse as V2 format (which includes both event and notificationSettings)
32+
logger.info('Attempting to parse as V2 payload');
33+
if (parsedData.event && parsedData.notificationSettings) {
34+
// This is a V2 payload
35+
const { event, notificationSettings } = parsedData;
36+
logger.info({ natsEventBodyV2: { event, notificationSettingsCount: notificationSettings.length } });
37+
response = await notificationService.sendNotificationV2(event, notificationSettings);
38+
} else {
39+
// Fall back to V1 format (which only includes the event)
40+
logger.info('Falling back to V1 payload format');
41+
const event = parsedData as Event;
42+
logger.info({ natsEventBodyV1: event });
43+
response = await notificationService.sendNotification(event);
44+
}
45+
} catch (error: any) {
46+
{
47+
logger.error(`Failed to process message in both V1 and V2 formats: ${error.message || 'Unknown error'}`);
48+
failedNotificationMetricsCounter.inc();
49+
throw error;
50+
}
51+
}
52+
53+
// Handle response metrics
54+
if (response.status != 0) {
55+
successNotificationMetricsCounter.inc();
56+
} else {
57+
failedNotificationMetricsCounter.inc();
58+
}
59+
};
60+
61+
export const connectToNats = async (notificationService: NotificationService) => {
62+
const natsUrl = process.env.NATS_URL;
63+
64+
if (!natsUrl) {
65+
logger.info("NATS_URL not provided, skipping NATS connection");
66+
return;
67+
}
68+
69+
try {
70+
logger.info("Connecting to NATS server...");
71+
const conn: NatsConnection = await connect({ servers: natsUrl });
72+
const jsm = await conn.jetstreamManager();
73+
const pubSubService = new PubSubServiceImpl(conn, jsm, logger);
74+
await pubSubService.Subscribe(NOTIFICATION_EVENT_TOPIC, natsEventHandler(notificationService));
75+
logger.info("Successfully connected to NATS");
76+
return conn;
77+
} catch (err) {
78+
logger.error("Error connecting to NATS:", err);
79+
}
80+
};

src/middleware/metrics.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (c) 2024. Devtron Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { Request, Response, NextFunction } from 'express';
18+
import { httpRequestMetricsCounter } from '../common/metrics';
19+
20+
export const metricsMiddleware = (req: Request, res: Response, next: NextFunction) => {
21+
httpRequestMetricsCounter.labels({
22+
method: req.method,
23+
endpoint: req.url,
24+
statusCode: res.statusCode
25+
}).inc();
26+
next();
27+
};

0 commit comments

Comments
 (0)