-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreadme.html
209 lines (199 loc) · 10.6 KB
/
readme.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Back-end Follower Maze Problem</title>
<style>
body {
display: flex;
}
body .container {
flex-direction: column;
flex: 1;
margin: 0 auto;
max-width: 1080px;
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
font-size: 14px;
color: #484848;
}
code {
background: #0c75ec;
padding: 1px 5px;
color: #FFFFFF;
border-radius: 3px;
}
.section {
background-color: #f5f5f5;
padding: 20px;
border: 3px;
margin-bottom: 20px;
text-align: justify;
}
h2 {
margin-top: 0;
}
.section .container {
padding-left: 20px;
}
.section.configuration li {
padding: 10px;
}
img {
border: 1px solid #DDDDDD;
margin: 5px;
}
</style>
</head>
<body>
<div class="container">
<h1 id="back-end-developer-challenge-follower-maze">Back-end Follower Maze Problem</h1>
<p>
<a href="assets/system.jpeg">
<img src="assets/system.jpeg" height="315">
</a>
<a href="assets/user_registration.jpeg">
<img src="assets/user_registration.jpeg" height="315">
</a>
<a href="assets//event_receiving.jpeg">
<img src="assets//event_receiving.jpeg" height="315">
</a>
<a href="assets/event_consuming.jpeg">
<img src="assets/event_consuming.jpeg" height="315">
</a>
</p>
<p>In this application, i tried to handle an unlimited event stream by creating a server. Server software flow charts and
it is overal design images are attached to this readme file. So i will explain the architecture of the solution with
these images.
</p>
<div class="section">
<h2 id="application-architecture-and-processes">Application Architecture and Processes</h2>
<p>When we have a look to the image
<code>Application Processes</code> we can see there are three threads runnning with the initialization. One thread for user registration, one for event
receiving and the last one for event consuming. Lets explain what they are doing exactly.</p>
<h3 id="user-registration-server">User Registration Server</h3>
<p>In the application, i am calling classes as server if they are listening a socket. So with this server we are listening
the registration port which is default 9099. This thread continuously listens connections and accept if there is.
Whenever a new socket created, this server assigns it to a user registration handler. Server creates this handler
threads from the connection pool. Server repeats these steps until the application shutdown.</p>
<div class="container">
<h4 id="user-registration-handler">User Registration Handler</h4>
<p>This is a thread for creating the user object with user id and accepted socket writer also adding this user to the
user map. This is a thread because we have to release the socket process as soon as possible we can. For the sake
of any other socket connections. In here handler reads the input stream of the socket until there is nothing in
it. For the each line, it creates a User object and sets the socket's output stream writer into user. This is because,
maybe this user will be get notified later. So the paylod of the notification will be send over this output stream
writer. Also users are containing the follower lists. After user creation this user is stored in a concurrent hash
map with the key as an id of user.</p>
</div>
<h3 id="event-receiver-server">Event Receiver Server</h3>
<p>With this server we are listening the registration port which is default 9090. This thread continuously listens connections
and accept if there is. Whenever a new socket created, this server assigns it to a event receiver handler. By the
way, according to my analysis there is only one event source is creating in our test scenario. Anyway server creates
this handler threads from the connection pool. Server repeats these steps until the application shutdown.</p>
<div class="container">
<h4 id="event-receiver-handler">Event Receiver Handler</h4>
<p>This is a thread for creating the event object and adding it to the priority blocking queue. This is a thread because
maybe later another event source wants to connect. In here handler reads the input stream of the socket, until
there is nothing in it. For the each line, it creates an Event object. In this event object there are event type,
from user id, to user id, payload itself and sequence. After event object creation, this event is added to the
event queue. This is a priority blocking queue. Which means you can put elements in it with your comparasition
logic. In our case Event class extends from a Comporator so we can compare each event object with their sequence
number. In our logic lower sequences are more close to the head of the queue. So please pay attention here because
this logic provides us an ordered queue by changing the head of the queue when we try to put a new item in it.</p>
</div>
<h3 id="event-consumer-manager">Event Consumer Manager</h3>
<p>This is another thread of our application. This thread compares the head's sequence of the event queue with a counted
sequence counter. When these sequences are equal this means that this event ready to ship. In order to do that it
calls consume event function from the event consumer object of it. We did it because it requested like that in the
instructions.
</p>
<div class="container">
<h4 id="envent-consumer">Envent Consumer</h4>
<p>This is an object in consumer manager. It responsibles to deliver the event to the related destination according
to it's type. Some of events are not suitable to deliver due to the rules. But still there could be some updates
on the user like updating the follower queue.</p>
<p>I will not explain the restrictions of the events deliviring because it is already explained in the requirements
document. But i will explain the challanges in this step.</p>
<p>When i start to test, i figured out that registered clients are getting new event requests from unregistered clients
so in order to over come the i start to create this unregistered users as dummy users and add them to the user
map. I have to do this because these dummy users followers needed to be notified in some cases. And those followers
could be registered ones and they were expecting to get this notification. After dummy user implementation everything
works fine.
</p>
</div>
</div>
<div class="section">
<h2 id="how-it-works">How It Works</h2>
<p>In this section i will explain how you can test both with the JAR file that you provided and with the unit tests and
integration tests.
</p>
<h3 id="for-unit-testing">For Unit Testing</h3>
<p>This project is created with gradle so it is enough to run
<code>gradle test --info</code> for unit tests.</p>
<h3 id="for-integration-testing">For Integration Testing</h3>
<p>I also added some integration tests. Which means real servers and a tcp client are created then start to send events.
I added another gradle task in my project for testing integration. To do that just run
<code>gradle integrationTest --info</code>
</p>
<h3 id="test-with-provided-jar">Test With Provided JAR</h3>
<p>To test with the jar that you provided, first you have to run my application. I suggest to run with
<code>./run.sh</code> file. Because you can set some enviromental variables before you run the application with sell script. (Please have
a look configuration section for details.) This will run the application in development mode. If you want to build
a JAR file of the application and running it, please run
<code>./run.sh --prod</code> command. This will run the all tests and build the application then create a JAR file under
<code>/build/libs/followermaze-server-all-1.0.jar</code>. Also it runs the application immediately. (Note a sample jar file is also added to the root of the project so maybe
you want to run this jar file directly and starts the app. This is just for any case for failed build.) And after
you see
<em>"Servers are up and running."</em> message you can run
<code>./followermaze.sh</code> and wait until the results are shown.</p>
<p>
<em>Please note that: You can run the application with default configs by running
<code>gradle run</code> command too on cli.</em>
</p>
</div>
<div class="section configuration">
<h2 id="configuration">Configuration</h2>
<p>You can run the application with the enviromental variables below:
<ul>
<li>
<strong>CONCURRENCY_LEVEL:</strong> This represents number of threads in your thread pool. If you set this one different
from
<code>0</code> this means your thread pool will have this number of threads. If you leave it as 0 this means that threads will
be created auto accordingly the app needs.
<code>Default is 0</code>.</li>
<li>
<strong>LOG_LEVEL</strong> You can set four log level.
<code>all</code>,
<code>debug</code>,
<code>info</code>,
<code>off</code>.
<code>Default is off</code>.</li>
<li>
<strong>REGISTRATION_SERVER_PORT</strong> Port for registration server.
<code>Default is 9099</code>.</li>
<li>
<strong>EVENT_RECEIVER_SERVER_PORT</strong> Port for event receiving server.
<code>Default is 9090</code>.</li>
</ul>
</p>
</div>
<div class="section">
<h2 id="logging">Logging</h2>
<p>Applicaiton uses log4j logging library. You can activate or deactivate logging. When ever it is activated it dumps
the log to the console and also it writes a new log file under
<code>/logs</code> folder.
</p>
</div>
<div class="section">
<h2 id="technology-used">Technology Used</h2>
<ul>
<li>Java 8</li>
<li>Gradle</li>
<li>Junit</li>
</ul>
</div>
</div>
</body>
</html>