Skip to content

Commit 7044355

Browse files
authored
Merge pull request #30 from soketi/feature/deprecation
Deprecated Echo Server in favour of pWS
2 parents f3402c3 + b64710d commit 7044355

File tree

6 files changed

+52
-52
lines changed

6 files changed

+52
-52
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
5353
- name: Load Kubernetes fixtures
5454
run: |
55-
kubectl apply -f tests/fixtures/echo.yaml
55+
kubectl apply -f tests/fixtures/pws.yaml
5656
5757
- name: Copy environment variables
5858
run: |

README.md

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
Echo Network Watcher
2-
=====================
1+
Soketi Network Watcher
2+
=======================
33

44
![CI](https://github.com/soketi/network-watcher/workflows/CI/badge.svg?branch=master)
55
[![codecov](https://codecov.io/gh/soketi/network-watcher/branch/master/graph/badge.svg)](https://codecov.io/gh/soketi/network-watcher)
@@ -9,13 +9,13 @@ Echo Network Watcher
99
![v1.20.6 K8s Version](https://img.shields.io/badge/K8s%20v1.20.6-Ready-%23326ce5?colorA=306CE8&colorB=green)
1010
![v1.21.0 K8s Version](https://img.shields.io/badge/K8s%20v1.21.0-Ready-%23326ce5?colorA=306CE8&colorB=green)
1111

12-
Monitor the [Echo Server](https://github.com/soketi/echo-server) container for memory allowance and new connections when running in Kubernetes.
12+
Monitor the [pWS server](https://github.com/soketi/pws) container for memory allowance and new connections when running in Kubernetes.
1313

1414
## 🤔 What does this controller solve?
1515

16-
If you run Echo Server standalone in a cluster, at scale, you might run into capacity issues: RAM usage might be near the limit and even if you decide to horizontally scale the pods, new connections might still come to pods that are near-limit and run into OOM at some point.
16+
If you run pWS standalone in a cluster, at scale, you might run into capacity issues: RAM usage might be near the limit and even if you decide to horizontally scale the pods, new connections might still come to pods that are near-limit and run into OOM at some point.
1717

18-
Running Network Watcher inside the same pod will solve the issues by continuously checking the Echo Server Usage API, labeling the pods that get over a specified threshold with `echo.soketi.app/accepts-new-connections: "no"`, so that the services watching for the pods will ignore them if also checking for this label:
18+
Running Network Watcher inside the same pod will solve the issues by continuously checking the pWS Server Usage API, labeling the pods that get over a specified threshold with `pws.soketi.app/accepts-new-connections: "no"`, so that the services watching for the pods will ignore them if also checking for this label:
1919

2020
```yaml
2121
spec:
@@ -24,22 +24,22 @@ spec:
2424
- port: 6001
2525
targetPort: 6001
2626
protocol: TCP
27-
name: echo
27+
name: pws
2828
selector:
2929
...
30-
echo.soketi.app/accepts-new-connections: "yes"
30+
pws.soketi.app/accepts-new-connections: "yes"
3131
```
3232
3333
## 🙌 Requirements
3434
3535
- PHP 8.0+
36-
- [Echo Server](https://github.com/soketi/echo-server) 5.3+
36+
- [pWS Server](https://github.com/soketi/pws) 1.0+
3737
3838
## Docker image
3939
4040
[Network Watcher is available via Docker](https://hub.docker.com/r/soketi/network-watcher). Use the images to run them into your cluster and use this project to develop the application.
4141
42-
[Network Watcher also comes with the Echo Server Helm chart](https://github.com/soketi/charts/tree/master/charts/echo-server). It just needs to be turned on if you need the network watcher and the according service annotations will be appended automatically.
42+
[Network Watcher also comes with the pWS Server Helm chart](https://github.com/soketi/charts/tree/master/charts/pws). It just needs to be turned on if you need the network watcher and the according service annotations will be appended automatically.
4343
4444
## 🚀 Installation
4545
@@ -59,7 +59,7 @@ $ php application network:watch
5959
| - | - | - | - |
6060
| `POD_NAMESPACE` | `--pod-namespace` | `default` | The Pod namespce to watch. |
6161
| `POD_NAME` | `--pod-name` | `some-pod` | The Pod name to watch. |
62-
| `ECHO_APP_PORT` | `--echo-app-port` | `6001` | The port number for the [Echo Server](https://github.com/soketi/echo-server) app. |
62+
| `SERVER_PORT` | `--server-port` | `6001` | The port number for the [pWS server](https://github.com/soketi/pws). |
6363
| `MEMORY_PERCENT` | `--memory-percent` | `75` | The threshold (in percent) that, once reached, the Pod will be marked as "not ready" to evict any new connections or requests. |
6464
| `CHECKING_INTERVAL` | `--checking-interval` | `1` | The amount of seconds to wait between API checks. |
6565
| `TEST_MODE` | `--test` | - | Run a single check rather than a continous loop of checks. |

app/Commands/WatchNetworkCommand.php

+11-11
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class WatchNetworkCommand extends Command implements SignalableCommandInterface
2222
protected $signature = 'network:watch
2323
{--pod-namespace=default : The Pod namespace. Defaults to the current Pod namespace.}
2424
{--pod-name=some-pod : The Pod name to watch. Defaults to the current Pod name.}
25-
{--echo-app-port=6001 : The Echo App socket port.}
25+
{--server-port=6001 : The Server port.}
2626
{--memory-percent=75 : The threshold at which new connections close for a specific server.}
2727
{--interval=1 : The interval in seconds between each checks.}
2828
{--test : Run only one loop for testing.}
@@ -33,7 +33,7 @@ class WatchNetworkCommand extends Command implements SignalableCommandInterface
3333
*
3434
* @var string
3535
*/
36-
protected $description = 'Run the Network watcher controller for the Echo app.';
36+
protected $description = 'Run the Network watcher controller for the pWS server.';
3737

3838
/**
3939
* The current pod the instance is running into.
@@ -76,7 +76,7 @@ public function getSubscribedSignals(): array
7676
public function handleSignal(int $signal): void
7777
{
7878
// Simply just mark the pod as rejecting the new connections while it's terminating.
79-
// This way, the Echo Server will close all existing connections internally,
79+
// This way, the pWS Server will close all existing connections internally,
8080
// but the Network Watcher will also mark the pod as not being able to receive new connections for
8181
// the sole purpose of redirecting the traffic to other pods.
8282
$this->pod->rejectNewConnections();
@@ -93,14 +93,14 @@ public function handle()
9393

9494
$podNamespace = env('POD_NAMESPACE') ?: $this->option('pod-namespace');
9595
$podName = env('POD_NAME') ?: $this->option('pod-name');
96-
$echoAppPort = env('ECHO_APP_PORT') ?: $this->option('echo-app-port');
96+
$serverPort = env('SERVER_PORT') ?: $this->option('server-port');
9797
$memoryThresholdPercent = env('MEMORY_PERCENT') ?: $this->option('memory-percent');
9898
$interval = env('CHECKING_INTERVAL') ?: $this->option('interval');
9999
$test = is_bool(env('TEST_MODE')) ? env('TEST_MODE') : $this->option('test');
100100

101101
$this->line("Namespace: {$podNamespace}");
102102
$this->line("Pod name: {$podName}");
103-
$this->line("Echo port: {$echoAppPort}");
103+
$this->line("Server port: {$serverPort}");
104104
$this->line("Memory threshold: {$memoryThresholdPercent}%");
105105
$this->line("Monitoring interval: {$interval}s");
106106

@@ -113,7 +113,7 @@ public function handle()
113113
}
114114

115115
while (true) {
116-
$this->checkPod($memoryThresholdPercent, $echoAppPort);
116+
$this->checkPod($memoryThresholdPercent, $serverPort);
117117

118118
sleep($interval);
119119

@@ -148,18 +148,18 @@ protected function registerPodMacros(): void
148148

149149
K8sPod::macro('acceptsConnections', function () {
150150
/** @var K8sPod $this */
151-
return $this->getLabel('echo.soketi.app/accepts-new-connections', 'yes') === 'yes';
151+
return $this->getLabel('pws.soketi.app/accepts-new-connections', 'yes') === 'yes';
152152
});
153153

154154
K8sPod::macro('rejectsConnections', function () {
155155
/** @var K8sPod $this */
156-
return $this->getLabel('echo.soketi.app/accepts-new-connections', 'yes') === 'no';
156+
return $this->getLabel('pws.soketi.app/accepts-new-connections', 'yes') === 'no';
157157
});
158158

159159
K8sPod::macro('acceptNewConnections', function () {
160160
/** @var K8sPod $this */
161161
$labels = array_merge($this->getLabels(), [
162-
'echo.soketi.app/accepts-new-connections' => 'yes',
162+
'pws.soketi.app/accepts-new-connections' => 'yes',
163163
]);
164164

165165
$this->refresh()->setLabels($labels)->update();
@@ -170,7 +170,7 @@ protected function registerPodMacros(): void
170170
K8sPod::macro('rejectNewConnections', function () {
171171
/** @var K8sPod $this */
172172
$labels = array_merge($this->getLabels(), [
173-
'echo.soketi.app/accepts-new-connections' => 'no',
173+
'pws.soketi.app/accepts-new-connections' => 'no',
174174
]);
175175

176176
$this->refresh()->setLabels($labels)->update();
@@ -180,7 +180,7 @@ protected function registerPodMacros(): void
180180

181181
K8sPod::macro('ensureItHasDefaultLabel', function () {
182182
/** @var K8sPod $this */
183-
if (! $this->getLabel('echo.soketi.app/accepts-new-connections')) {
183+
if (! $this->getLabel('pws.soketi.app/accepts-new-connections')) {
184184
$this->acceptNewConnections();
185185
}
186186
});

app/Concerns/ChecksCurrentPod.php

+13-13
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ trait ChecksCurrentPod
1010
* Check the pod metrics to adjust new connection allowance.
1111
*
1212
* @param float $memoryThresholdPercent
13-
* @param int $echoAppPort
13+
* @param int $serverPort
1414
* @return void
1515
*/
16-
protected function checkPod(float $memoryThresholdPercent, int $echoAppPort): void
16+
protected function checkPod(float $memoryThresholdPercent, int $serverPort): void
1717
{
1818
/** @var \App\Commands\WatchNetworkCommand $this */
19-
$usedMemoryPercent = $this->getEchoServerMemoryUsagePercent($echoAppPort);
19+
$usedMemoryPercent = $this->getServerMemoryUsagePercent($serverPort);
2020
$dateTime = now()->toDateTimeString();
2121

2222
$this->line("[{$dateTime}] Current memory usage is {$usedMemoryPercent}%. Checking...", null, 'v');
@@ -26,14 +26,14 @@ protected function checkPod(float $memoryThresholdPercent, int $echoAppPort): vo
2626
if ($usedMemoryPercent >= $memoryThresholdPercent) {
2727
if ($this->pod->acceptsConnections()) {
2828
$this->info("[{$dateTime}] Pod now rejects connections.");
29-
$this->info("[{$dateTime}] Echo container uses {$usedMemoryPercent}%, threshold is {$memoryThresholdPercent}%");
29+
$this->info("[{$dateTime}] Server container uses {$usedMemoryPercent}%, threshold is {$memoryThresholdPercent}%");
3030

3131
$this->rejectNewConnections($usedMemoryPercent, $memoryThresholdPercent);
3232
}
3333
} else {
3434
if ($this->pod->rejectsConnections()) {
3535
$this->info("[{$dateTime}] Pod now accepts connections.");
36-
$this->info("[{$dateTime}] Echo container uses {$usedMemoryPercent}%, threshold is {$memoryThresholdPercent}%");
36+
$this->info("[{$dateTime}] Server container uses {$usedMemoryPercent}%, threshold is {$memoryThresholdPercent}%");
3737

3838
$this->acceptNewConnections($usedMemoryPercent, $memoryThresholdPercent);
3939
}
@@ -55,7 +55,7 @@ protected function rejectNewConnections(float $usedMemoryPercent, float $memoryT
5555
$now = now()->toIso8601String();
5656

5757
$this->pod->newEvent()
58-
->setMessage("Rejecting new connections. Echo container uses {$usedMemoryPercent}%, threshold is {$memoryThresholdPercent}%")
58+
->setMessage("Rejecting new connections. Server container uses {$usedMemoryPercent}%, threshold is {$memoryThresholdPercent}%")
5959
->setReason('OverThreshold')
6060
->setType('Warning')
6161
->setFirstTimestamp($now)
@@ -78,7 +78,7 @@ protected function acceptNewConnections(float $usedMemoryPercent, float $memoryT
7878
$now = now()->toIso8601String();
7979

8080
$this->pod->newEvent()
81-
->setMessage("Accepting new connections. Echo container uses {$usedMemoryPercent}%, threshold is {$memoryThresholdPercent}%")
81+
->setMessage("Accepting new connections. Server container uses {$usedMemoryPercent}%, threshold is {$memoryThresholdPercent}%")
8282
->setReason('BelowThreshold')
8383
->setType('Normal')
8484
->setFirstTimestamp($now)
@@ -89,23 +89,23 @@ protected function acceptNewConnections(float $usedMemoryPercent, float $memoryT
8989
/**
9090
* Get the pod metrics from the Usage API.
9191
*
92-
* @param int $echoAppPort
92+
* @param int $serverPort
9393
* @return array
9494
*/
95-
protected function getUsage(int $echoAppPort): array
95+
protected function getUsage(int $serverPort): array
9696
{
97-
return Http::get("http://localhost:{$echoAppPort}/usage")->json();
97+
return Http::get("http://localhost:{$serverPort}/usage")->json();
9898
}
9999

100100
/**
101101
* Get the percent of used memory from the Usage API.
102102
*
103-
* @param int $echoAppPort
103+
* @param int $serverPort
104104
* @return float
105105
*/
106-
protected function getEchoServerMemoryUsagePercent(int $echoAppPort): float
106+
protected function getServerMemoryUsagePercent(int $serverPort): float
107107
{
108-
$usage = $this->getUsage($echoAppPort);
108+
$usage = $this->getUsage($serverPort);
109109

110110
return $usage['memory']['percent'] ?? 0.00;
111111
}

tests/Feature/NetworkWatchTest.php

+10-10
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class NetworkWatchTest extends TestCase
1414
public function test_watch_pod_rejecting_connections()
1515
{
1616
/** @var \RenokiCo\PhpK8s\Kinds\K8sDeployment $deployment */
17-
$deployment = LaravelK8s::getDeploymentByName('echo-server-test');
17+
$deployment = LaravelK8s::getDeploymentByName('pws-server-test');
1818

1919
while (! $deployment->allPodsAreRunning()) {
2020
echo "Waiting for {$deployment->getName()} deployment to have pods running...";
@@ -34,15 +34,15 @@ public function test_watch_pod_rejecting_connections()
3434
$this->artisan('network:watch', [
3535
'--pod-namespace' => 'default',
3636
'--pod-name' => $pod->getName(),
37-
'--echo-app-port' => 6001,
37+
'--server-port' => 6001,
3838
'--memory-percent' => 80,
3939
'--interval' => 1,
4040
'--test' => true,
4141
]);
4242

4343
$pod->refresh();
4444

45-
$this->assertEquals('no', $pod->getLabel('echo.soketi.app/accepts-new-connections'));
45+
$this->assertEquals('no', $pod->getLabel('pws.soketi.app/accepts-new-connections'));
4646

4747
$event = $pod->getEvents()->reverse()->first(function ($event) use ($pod) {
4848
return $event->getAttribute('involvedObject.name') === $pod->getName() &&
@@ -55,7 +55,7 @@ public function test_watch_pod_rejecting_connections()
5555
public function test_watch_pod_accepting_connections()
5656
{
5757
/** @var \RenokiCo\PhpK8s\Kinds\K8sDeployment $deployment */
58-
$deployment = LaravelK8s::getDeploymentByName('echo-server-test');
58+
$deployment = LaravelK8s::getDeploymentByName('pws-server-test');
5959

6060
while (! $deployment->allPodsAreRunning()) {
6161
echo "Waiting for {$deployment->getName()} deployment to have pods running...";
@@ -75,21 +75,21 @@ public function test_watch_pod_accepting_connections()
7575
$this->artisan('network:watch', [
7676
'--pod-namespace' => 'default',
7777
'--pod-name' => $pod->getName(),
78-
'--echo-app-port' => 6001,
78+
'--server-port' => 6001,
7979
'--memory-percent' => 90,
8080
'--interval' => 1,
8181
'--test' => true,
8282
]);
8383

8484
$pod->refresh();
8585

86-
$this->assertEquals('yes', $pod->getLabel('echo.soketi.app/accepts-new-connections'));
86+
$this->assertEquals('yes', $pod->getLabel('pws.soketi.app/accepts-new-connections'));
8787
}
8888

8989
public function test_signaling_should_incapacitate_the_pod()
9090
{
9191
/** @var \RenokiCo\PhpK8s\Kinds\K8sDeployment $deployment */
92-
$deployment = LaravelK8s::getDeploymentByName('echo-server-test');
92+
$deployment = LaravelK8s::getDeploymentByName('pws-server-test');
9393

9494
while (! $deployment->allPodsAreRunning()) {
9595
echo "Waiting for {$deployment->getName()} deployment to have pods running...";
@@ -102,7 +102,7 @@ public function test_signaling_should_incapacitate_the_pod()
102102

103103
$pod = $this->makePodAcceptNewConnections($pod, true);
104104

105-
$this->assertEquals('yes', $pod->getLabel('echo.soketi.app/accepts-new-connections'));
105+
$this->assertEquals('yes', $pod->getLabel('pws.soketi.app/accepts-new-connections'));
106106

107107
/** @var WatchNetworkCommand $command */
108108
$command = app(WatchNetworkCommand::class);
@@ -115,7 +115,7 @@ public function test_signaling_should_incapacitate_the_pod()
115115

116116
$pod->refresh();
117117

118-
$this->assertEquals('no', $pod->getLabel('echo.soketi.app/accepts-new-connections'));
118+
$this->assertEquals('no', $pod->getLabel('pws.soketi.app/accepts-new-connections'));
119119

120120
$event = $pod->getEvents()->reverse()->first(function ($event) use ($pod) {
121121
return $event->getAttribute('involvedObject.name') === $pod->getName() &&
@@ -135,7 +135,7 @@ public function test_signaling_should_incapacitate_the_pod()
135135
protected function makePodAcceptNewConnections(K8sPod $pod, $accept = true)
136136
{
137137
$labels = array_merge($pod->getLabels(), [
138-
'echo.soketi.app/accepts-new-connections' => $accept ? 'yes' : 'no',
138+
'pws.soketi.app/accepts-new-connections' => $accept ? 'yes' : 'no',
139139
]);
140140

141141
$pod->refresh()->setLabels($labels)->update();

tests/fixtures/echo.yaml tests/fixtures/pws.yaml

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
apiVersion: apps/v1
22
kind: Deployment
33
metadata:
4-
name: echo-server-test
4+
name: pws-server-test
55
labels:
6-
app: echo-server-test
6+
app: pws-server-test
77
state: testing
88
spec:
99
replicas: 1
1010
selector:
1111
matchLabels:
12-
app: echo-server-test
12+
app: pws-server-test
1313
state: testing
1414
template:
1515
metadata:
1616
labels:
17-
app: echo-server-test
17+
app: pws-server-test
1818
state: testing
19-
deployment-name: echo-server-test
19+
deployment-name: pws-server-test
2020
spec:
2121
containers:
22-
- name: echo
23-
image: soketi/echo-server:5.3-14-alpine
22+
- name: pws
23+
image: soketi/pws-0.1-14-alpine
2424
env:
2525
- name: PRESENCE_STORAGE_DATABASE
2626
value: socket

0 commit comments

Comments
 (0)