Skip to content

Commit

Permalink
finished error handling and docker compose configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
MohammedArab1 committed Jul 7, 2024
1 parent 7676f16 commit 7bbb3bd
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 50 deletions.
20 changes: 18 additions & 2 deletions API/src/graphql.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,15 @@ const resolvers = {
const server = new ApolloServer({
typeDefs,
resolvers,
cache: new KeyvAdapter(new Keyv('redis://localhost:6379')),
cache: new KeyvAdapter(
new Keyv(process.env.REDIS_URL, {
retryStrategy(times) {
return false;
},
}).on('error', (err) => {
console.log('error on keyv connection ');
})
),
plugins: [
ApolloServerPluginCacheControl({ defaultMaxAge: 3600 }),
responseCachePlugin.default(),
Expand All @@ -194,4 +202,12 @@ const server = new ApolloServer({
},
});

module.exports = { server };
const serverNoCaching = new ApolloServer({
typeDefs,
resolvers,
formatError: (err) => {
return err.message;
},
});

module.exports = { server, serverNoCaching };
86 changes: 60 additions & 26 deletions API/src/index.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
require("dotenv").config();
const express = require("express");
const cors = require("cors");
const app = express();
const swaggerJsdoc = require('swagger-jsdoc');
const swaggerUi = require('swagger-ui-express');
const {server} = require("./graphql.js")
const {server, serverNoCaching} = require("./graphql.js")
const {expressMiddleware} = require("@apollo/server/express4")
const {addRestRoutes} = require("./rest.js")
const {createClient} = require("redis")

const startGqlServer = async () => {
await server.start()
app.use('/graphql', expressMiddleware(server));
console.log("Graphql server started")
var expressServer = null
var gqlRedisServerStarted = false
var redisClientReady = true

const startGqlServer = async (app,client) => {
if (client) {
await server.start()
gqlRedisServerStarted = true
app.use('/graphql', expressMiddleware(server));
console.log("Graphql server with redis started")
}
else {
await serverNoCaching.start()
app.use('/graphql', expressMiddleware(serverNoCaching));
console.log("Graphql server without redis started")
}
}

//todo:handle redis disconnection gracefully, add redis to docker compose, remove need for redis when in dev
const redisMiddleware = async function (req, res, next) {
cache = await client.get(req.originalUrl)
if (cache) {
Expand All @@ -26,15 +36,15 @@ const redisMiddleware = async function (req, res, next) {
}
}

const startApp = async () => {
client = await createClient()
.on('error', err => console.log('Redis Client Error', err))
.connect()

const startApp = async (client=null) => {
const app = express();
app.use(express.json());
app.use(cors());
app.use(redisMiddleware)
if (client) {
app.use(redisMiddleware)
}
addRestRoutes(app, client)

const options = {
definition: {
openapi: '3.0.0',
Expand All @@ -48,19 +58,43 @@ const startApp = async () => {
const openapiSpecification = swaggerJsdoc(options);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(openapiSpecification));
const PORT = process.env.PORT || 3001
await startGqlServer()
app.listen(PORT,() => {`Server running on port ${PORT}`})

await startGqlServer(app,client)
var server = app.listen(PORT,() => {`Server running on port ${PORT}`})
return server
}

startApp()

const startRedis = async () => {
client = await createClient({
url: process.env.REDIS_URL,
socket: {
reconnectStrategy: false
}
})
.on('error', async (err) => {
console.log("error connecting to redis")
if (expressServer) {
expressServer.close()
console.log("express server stopped")
}
if (server && gqlRedisServerStarted) {
await server.stop()
gqlRedisServerStarted = false
console.log("Graphql server stopped")
}
expressServer = await startApp()
})
.on('ready', async ()=>{
redisClientReady = true
})
.connect()
if (redisClientReady){
expressServer = await startApp(client)
}
}

// const dev = process.argv.indexOf('--dev');
// if (dev > -1){
// const PORT = process.env.PORT || 3001
// startGqlServer()
// app.listen(PORT,() => {`Server running on port ${PORT}`})
// } else {
// module.exports = app;
// }
if (process.env.CACHE.toLowerCase() == "true"){
startRedis()
}
else {
expressServer = startApp()
}
60 changes: 38 additions & 22 deletions API/src/rest.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ const addRestRoutes = (app, redisClient) => {
bookNames.sort((a, b) => {
return utils.compareAlphabetically(a.bookId, b.bookId);
});
await redisClient.set(request.originalUrl,JSON.stringify(bookNames),{
EX: 600,
})
if (redisClient) {
await redisClient.set(request.originalUrl,JSON.stringify(bookNames),{
EX: 600,
})
}
return response.json(bookNames);
};
};
Expand Down Expand Up @@ -132,17 +134,23 @@ const addRestRoutes = (app, redisClient) => {
hadiths['englishQueryResults'].length === 0 &&
hadiths['arabicQueryResults'].length === 0
) {
await redisClient.set(request.path,express.json.stringify({ error: 'No matches found' }))
if (redisClient) {
await redisClient.set(request.path,express.json.stringify({ error: 'No matches found' }))
}
return response.json({ error: 'No matches found' });
} else if (hadiths['englishQueryResults'].length > 0) {
await redisClient.set(request.originalUrl,JSON.stringify(hadiths['englishQueryResults']),{
EX: 60,
})
if (redisClient) {
await redisClient.set(request.originalUrl,JSON.stringify(hadiths['englishQueryResults']),{
EX: 60,
})
}
return response.json(hadiths['englishQueryResults']);
} else if (hadiths['arabicQueryResults'].length > 0) {
await redisClient.set(request.originalUrl,JSON.stringify(hadiths['arabicQueryResults']),{
EX: 60,
})
if (redisClient) {
await redisClient.set(request.originalUrl,JSON.stringify(hadiths['arabicQueryResults']),{
EX: 60,
})
}
return response.json(hadiths['arabicQueryResults']);
}
}
Expand Down Expand Up @@ -225,14 +233,18 @@ const addRestRoutes = (app, redisClient) => {
) {
return response.json({ error: 'No matches found' });
} else if (hadiths['englishQueryResults'].length > 0) {
await redisClient.set(request.originalUrl,JSON.stringify(hadiths['englishQueryResults']),{
EX: 60,
})
if (redisClient) {
await redisClient.set(request.originalUrl,JSON.stringify(hadiths['englishQueryResults']),{
EX: 60,
})
}
return response.json(hadiths['englishQueryResults']);
} else if (hadiths['arabicQueryResults'].length > 0) {
await redisClient.set(request.originalUrl,JSON.stringify(hadiths['arabicQueryResults']),{
EX: 60,
})
if (redisClient) {
await redisClient.set(request.originalUrl,JSON.stringify(hadiths['arabicQueryResults']),{
EX: 60,
})
}
return response.json(hadiths['arabicQueryResults']);
}
}
Expand Down Expand Up @@ -329,9 +341,11 @@ const addRestRoutes = (app, redisClient) => {
hadiths.sort((a, b) => {
return a['id'] - b['id'];
});
await redisClient.set(request.originalUrl,JSON.stringify(hadiths),{
EX: 3600,
})
if (redisClient) {
await redisClient.set(request.originalUrl,JSON.stringify(hadiths),{
EX: 3600,
})
}
return response.json(hadiths);
}
};
Expand Down Expand Up @@ -457,9 +471,11 @@ const addRestRoutes = (app, redisClient) => {
} else if (hadith.length === 0) {
return response.status(400).json({ error: invalidId });
} else {
await redisClient.set(request.originalUrl,JSON.stringify(hadith),{
EX: 600,
})
if (redisClient) {
await redisClient.set(request.originalUrl,JSON.stringify(hadith),{
EX: 600,
})
}
return response.json(hadith);
}
}
Expand Down
12 changes: 12 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ services:
environment:
MONGODB_URI: ${MONGODB_URI}
PORT: ${PORT}
CACHE: ${CACHE}
REDIS_URL: ${REDIS_URL}
depends_on:
- redis
caddy:
container_name: caddy
image: caddy
Expand All @@ -32,6 +36,14 @@ services:
- /root/.docker/config.json:/config.json
- /var/run/docker.sock:/var/run/docker.sock
command: --interval 30
redis:
container_name: redis
image: redis/redis-stack-server
restart: no
networks:
- apinetwork
labels:
- "com.centurylinklabs.watchtower.enable=false"

networks:
apinetwork:

0 comments on commit 7bbb3bd

Please sign in to comment.