Skip to content

Commit 3e26a95

Browse files
committed
Merge branch 'part_five_elastic' into part_five
2 parents 1223c42 + 63f17c0 commit 3e26a95

File tree

13 files changed

+279
-25
lines changed

13 files changed

+279
-25
lines changed

.github/workflows/nodejs.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ jobs:
1010
matrix:
1111
node-version: [12.x, 14.x]
1212
mongodb-version: [4.0, 4.2]
13+
elasticsearch-version: ['7.9.3']
1314

1415
steps:
1516
- uses: actions/checkout@v1
@@ -21,6 +22,21 @@ jobs:
2122
uses: wbari/[email protected]
2223
with:
2324
mongoDBVersion: ${{ matrix.mongodb-version }}
25+
- name: Configure sysctl limits
26+
run: |
27+
sudo swapoff -a
28+
sudo sysctl -w vm.swappiness=1
29+
sudo sysctl -w fs.file-max=262144
30+
sudo sysctl -w vm.max_map_count=262144
31+
- name: Launch elasticsearch
32+
uses: getong/[email protected]
33+
with:
34+
elasticsearch version: ${{ matrix.elasticsearch-version }}
35+
host port: 9200
36+
container port: 9200
37+
host node port: 9300
38+
node port: 9300
39+
discovery type: 'single-node'
2440
- name: npm install, build, and test
2541
run: |
2642
npm install

docker-compose.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ x-app-service: &default-app
77
- MONGO_URL=mongodb://mongo:27017/dev
88
depends_on:
99
- mongo
10+
- kibana
11+
- elasticsearch
1012
volumes:
1113
- .:/code:delegated
1214
- node_modules:/code/node_modules:delegated
@@ -34,5 +36,33 @@ services:
3436
ports:
3537
- 27017:27017
3638

39+
elasticsearch:
40+
image: docker.elastic.co/elasticsearch/elasticsearch:7.9.3
41+
container_name: codely-elasticsearch
42+
environment:
43+
- node.name=codely-elasticsearch
44+
- discovery.type=single-node #Elasticsearch forms a single-node cluster
45+
- bootstrap.memory_lock=true # might cause the JVM or shell session to exit if it tries to allocate more memory than is available!
46+
- 'ES_JAVA_OPTS=-Xms512m -Xmx512m'
47+
ulimits:
48+
memlock:
49+
soft: -1 # The memlock soft and hard values configures the range of memory that ElasticSearch will use. Setting this to –1 means unlimited.
50+
hard: -1
51+
volumes:
52+
- esdata:/usr/share/elasticsearch/data
53+
ports:
54+
- '9200:9200'
55+
56+
kibana:
57+
image: docker.elastic.co/kibana/kibana:7.8.1
58+
container_name: codely-kibana
59+
environment:
60+
ELASTICSEARCH_URL: http://codely-elasticsearch:9200
61+
ELASTICSEARCH_HOSTS: http://codely-elasticsearch:9200
62+
ports:
63+
- 5601:5601
64+
3765
volumes:
3866
node_modules:
67+
esdata:
68+
driver: local

package-lock.json

Lines changed: 45 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"cypress:run": "NODE_ENV=test ts-node tests/utils/cypress/run"
3232
},
3333
"dependencies": {
34+
"@elastic/elasticsearch": "^7.9.1",
3435
"@types/bson": "^4.0.2",
3536
"@types/compression": "^1.7.0",
3637
"@types/convict": "^5.2.1",
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { ElasticRepository } from '../../Shared/infrastructure/persistence/elasticsearch/ElasticRepository';
2+
import { BackofficeCourse } from '../domain/BackofficeCourse';
3+
import { BackofficeCourseRepository } from '../domain/BackofficeCourseRepository';
4+
5+
type ElasticBackofficeCourseDocument = { _source: { id: string; duration: string; name: string } };
6+
7+
export class ElasticBackofficeCourseRepository
8+
extends ElasticRepository<BackofficeCourse>
9+
implements BackofficeCourseRepository {
10+
protected moduleName(): string {
11+
return 'backofficecourses';
12+
}
13+
14+
async searchAll(): Promise<BackofficeCourse[]> {
15+
const client = await this.client();
16+
17+
const response = await client.search({
18+
index: this.moduleName(),
19+
body: {
20+
query: {
21+
match_all: {}
22+
}
23+
}
24+
});
25+
26+
return response.body.hits.hits.map((hit: ElasticBackofficeCourseDocument) =>
27+
BackofficeCourse.fromPrimitives({ ...hit._source })
28+
);
29+
}
30+
31+
async save(course: BackofficeCourse): Promise<void> {
32+
return this.persist(this.moduleName(), course);
33+
}
34+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Client as ElasticClient } from '@elastic/elasticsearch';
2+
import config from '../../../../../apps/backoffice/backend/config/config';
3+
import { Nullable } from '../../../domain/Nullable';
4+
5+
export class ElasticClientFactory {
6+
private static clients: { [key: string]: ElasticClient } = {};
7+
8+
static async createClient(contextName: string): Promise<ElasticClient> {
9+
let client = ElasticClientFactory.getClient(contextName);
10+
11+
if (!client) {
12+
client = await ElasticClientFactory.createAndConnectClient();
13+
14+
ElasticClientFactory.registerClient(client, contextName);
15+
}
16+
17+
return client;
18+
}
19+
20+
private static getClient(contextName: string): Nullable<ElasticClient> {
21+
return ElasticClientFactory.clients[contextName];
22+
}
23+
24+
private static async createAndConnectClient(): Promise<ElasticClient> {
25+
const client = new ElasticClient({ node: config.get('elastic.url') });
26+
27+
return client;
28+
}
29+
30+
private static registerClient(client: ElasticClient, contextName: string): void {
31+
ElasticClientFactory.clients[contextName] = client;
32+
}
33+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Client as ElasticClient } from '@elastic/elasticsearch';
2+
import { AggregateRoot } from '../../../../Mooc/Courses/domain/AggregateRoot';
3+
4+
export abstract class ElasticRepository<T extends AggregateRoot> {
5+
constructor(private _client: Promise<ElasticClient>) {}
6+
7+
protected abstract moduleName(): string;
8+
9+
protected client(): Promise<ElasticClient> {
10+
return this._client;
11+
}
12+
13+
protected async persist(index: string, aggregateRoot: T): Promise<void> {
14+
const document = { ...aggregateRoot.toPrimitives() };
15+
const client = await this.client();
16+
17+
await client.index({ index: index, body: document, refresh: 'wait_for' }); // wait_for wait for a refresh to make this operation visible to search
18+
}
19+
}

src/apps/backoffice/backend/config/config.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ const convictConfig = convict({
1414
env: 'MONGO_URL',
1515
default: 'mongodb://localhost:27017/backoffice-backend-dev'
1616
}
17+
},
18+
elastic: {
19+
url: {
20+
doc: 'The Elastic connection URL',
21+
format: String,
22+
env: 'ELASTIC_URL',
23+
default: 'http://localhost:9200'
24+
}
1725
}
1826
});
1927

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
11
services:
2-
Backoffice.Backend.courses.BackofficeCourseRepository:
3-
class: ../../../../../../Contexts/Backoffice/Shared/infrastructure/MongoBackofficeCourseRepository
4-
arguments: ['@Shared.ConnectionManager']
2+
Backoffice.Backend.courses.BackofficeCourseRepository:
3+
class: ../../../../../../Contexts/Backoffice/Shared/infrastructure/MongoBackofficeCourseRepository
4+
arguments: ['@Shared.ConnectionManager']
55

6-
Backoffice.Backend.courses.CoursesFinder:
7-
class: ../../../../../../Contexts/Backoffice/SearchAll/application//CoursesFinder
8-
arguments: ["@Backoffice.Backend.courses.BackofficeCourseRepository"]
6+
Backoffice.Backend.courses.BackofficeCourseRepositoryElastic:
7+
class: ../../../../../../Contexts/Backoffice/infrastructure/ElasticBackofficeCourseRepository
8+
arguments: ['@Shared.ConnectionManagerElastic']
99

10-
Backoffice.Backend.courses.SearchAllCoursesQueryHandler:
11-
class: ../../../../../../Contexts/Backoffice/SearchAll/application//SearchAllCoursesQueryHandler
12-
arguments: ["@Backoffice.Backend.courses.CoursesFinder"]
13-
tags:
14-
- { name: 'queryHandler' }
10+
Backoffice.Backend.courses.CoursesFinder:
11+
class: ../../../../../../Contexts/Backoffice/SearchAll/application//CoursesFinder
12+
arguments: ['@Backoffice.Backend.courses.BackofficeCourseRepository']
1513

16-
Backoffice.Backend.courses.BackofficeCourseCreator:
17-
class: ../../../../../../Contexts/Backoffice/Courses/application/BackofficeCourseCreator
18-
arguments: ["@Backoffice.Backend.courses.BackofficeCourseRepository"]
14+
Backoffice.Backend.courses.SearchAllCoursesQueryHandler:
15+
class: ../../../../../../Contexts/Backoffice/SearchAll/application//SearchAllCoursesQueryHandler
16+
arguments: ['@Backoffice.Backend.courses.CoursesFinder']
17+
tags:
18+
- { name: 'queryHandler' }
1919

20-
Backoffice.Backend.courses.CreateBackofficeCourseOnCourseCreated:
21-
class: ../../../../../../Contexts/Backoffice/Courses/application/CreateBackofficeCourseOnCourseCreated
22-
arguments: ['@Backoffice.Backend.courses.BackofficeCourseCreator']
23-
tags:
24-
- { name: 'domainEventSubscriber' }
20+
Backoffice.Backend.courses.BackofficeCourseCreator:
21+
class: ../../../../../../Contexts/Backoffice/Courses/application/BackofficeCourseCreator
22+
arguments: ['@Backoffice.Backend.courses.BackofficeCourseRepository']
2523

24+
Backoffice.Backend.courses.CreateBackofficeCourseOnCourseCreated:
25+
class: ../../../../../../Contexts/Backoffice/Courses/application/CreateBackofficeCourseOnCourseCreated
26+
arguments: ['@Backoffice.Backend.courses.BackofficeCourseCreator']
27+
tags:
28+
- { name: 'domainEventSubscriber' }

src/apps/backoffice/backend/config/dependency-injection/Shared/application.yaml

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
services:
22
Shared.Logger:
3-
class: ../../../../../../Contexts/Shared/infrastructure/WinstonLogger
3+
class: ../../../../../../Contexts/Shared/infrastructure/WinstonLogger
44
arguments: []
55

66
Shared.ConnectionManager:
77
factory:
8-
class: ../../../../../../Contexts/Shared/infrastructure/persistence/mongo/MongoClientFactory
8+
class: ../../../../../../Contexts/Shared/infrastructure/persistence/mongo/MongoClientFactory
9+
method: 'createClient'
10+
arguments: ['mooc']
11+
12+
Shared.ConnectionManagerElastic:
13+
factory:
14+
class: ../../../../../../Contexts/Shared/infrastructure/persistence/elasticsearch/ElasticClientFactory
915
method: 'createClient'
1016
arguments: ['mooc']
1117

@@ -18,7 +24,7 @@ services:
1824
arguments: ['@Shared.QueryHandlersInformation']
1925

2026
Shared.EventBus:
21-
class: ../../../../../../Contexts/Shared/infrastructure/EventBus/InMemorySyncEventBus
27+
class: ../../../../../../Contexts/Shared/infrastructure/EventBus/InMemorySyncEventBus
2228
arguments: []
2329

2430
Shared.EventBus.DomainEventMapping:

0 commit comments

Comments
 (0)