Skip to content

Commit

Permalink
Update instance shutdown procedure (#171)
Browse files Browse the repository at this point in the history
  • Loading branch information
maddsua authored Feb 14, 2024
1 parent 8fb48b1 commit 1fad21f
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 16 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/testbuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ jobs:
- name: HTTP/Headers test
run: make test.headers

# Instance restart test doesn't really show anything unless the instance gets some requests first,
# and setting that up is not on my list right now
# - name: Instance restart test
# run: make test.instance_restart

build_examples:
needs: build_lib
runs-on: ubuntu-latest
Expand Down
48 changes: 35 additions & 13 deletions core/server/instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,6 @@ LambdaInstance::LambdaInstance(RequestCallback handlerCallback, ServerConfig ini
this->m_connections.remove_if(workerJoinFilter);
}
}

// Request all workers to exit
for (auto& worker : this->m_connections) {
worker.shutdownFlag = true;
}

// Wait untill all workers done
for (auto& item : this->m_connections) {
if (item.worker.joinable()) {
item.worker.join();
}
}
});

if (config.loglevel.startMessage) {
Expand All @@ -88,18 +76,52 @@ void LambdaInstance::shutdownn() {
}

void LambdaInstance::terminate() {

// reqeust service worker to exit
this->m_terminated = true;

// close listen socket
this->listener.stop();
this->awaitFinished();

// Request all connection workers to exit
for (auto& worker : this->m_connections) {
worker.shutdownFlag = true;
}
}

void LambdaInstance::awaitFinished() {

// wait until service worker exits
if (this->serviceWorker.valid())
this->serviceWorker.get();

// Wait until all connection workers done
for (auto& item : this->m_connections) {
if (item.worker.joinable()) {
item.worker.join();
}
}
}

LambdaInstance::~LambdaInstance() {

// send terminate "signals"
this->terminate();

// Wait until service worker exits.
// Copypasted a bit but it's better than adding arguments to awaitFinished()
// just to accound for exception suppression
if (this->serviceWorker.valid()) {
try { this->serviceWorker.get(); }
catch(...) {}
}

// Wait until all connection workers exited
for (auto& item : this->m_connections) {
if (item.worker.joinable()) {
item.worker.join();
}
}
}

const ServerConfig& LambdaInstance::getConfig() const noexcept {
Expand Down
15 changes: 14 additions & 1 deletion core/server/server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,31 @@ namespace Lambda {

std::future<void> serviceWorker;
std::forward_list<WorkerContext> m_connections;
std::atomic<size_t> m_connections_count {0};
std::atomic<size_t> m_connections_count = 0;
bool m_terminated = false;

/**
* Internal call that signals all workers to exit
*/
void terminate();

public:
LambdaInstance(RequestCallback handlerCallback, ServerConfig init);
~LambdaInstance();

/**
* Stop server
*/
void shutdownn();

/**
* Block current thread until server exits
*/
void awaitFinished();

/**
* Return current instance config
*/
const ServerConfig& getConfig() const noexcept;
};
};
Expand Down
4 changes: 2 additions & 2 deletions examples/reply/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

using namespace Lambda;

auto requestHandler = [](const Request& req, const Context& context) {
auto requestHandlerA = [](const Request& req, const Context& context) {
const auto uaHeader = req.headers.get("user-agent");
const auto uaString = uaHeader.size() ? uaHeader : "Unknown";
return Response("Your user-agent is: " + uaString);
Expand All @@ -22,7 +22,7 @@ int main(int argc, char const *argv[]) {

ServerConfig initparams;
initparams.loglevel.requests = true;
auto server = LambdaInstance(requestHandler, initparams);
auto server = LambdaInstance(requestHandlerA, initparams);

server.awaitFinished();

Expand Down
36 changes: 36 additions & 0 deletions tests/instance_restart/instance_restart.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@

#include "../../lambda.hpp"
using namespace Lambda;

const auto requestHandlerA = [](const Request& req, const Context& context) {
return Response("Response from instance A");
};

const auto requestHandlerB = [](const Request& req, const Context& context) {
return Response("Response from instance B");
};

int main(int argc, char const *argv[]) {

{
puts("Starting instance A...");
auto serverA = LambdaInstance(requestHandlerA, {});
std::thread([&](){
std::this_thread::sleep_for(std::chrono::milliseconds(1500));
serverA.shutdownn();
}).detach();
serverA.awaitFinished();
}

{
puts("Starting instance B...");
auto serverB = LambdaInstance(requestHandlerB, {});
std::thread([&](){
std::this_thread::sleep_for(std::chrono::milliseconds(1500));
serverB.shutdownn();
}).detach();
serverB.awaitFinished();
}

return 0;
}
11 changes: 11 additions & 0 deletions tests/instance_restart/instance_restart.test.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

# instance restart test
TEST_INSTANCE_RESTART_TARGET = instance_restart.test$(EXEEXT)
test.instance_restart: $(TEST_INSTANCE_RESTART_TARGET)
$(TEST_INSTANCE_RESTART_TARGET)

$(TEST_INSTANCE_RESTART_TARGET): tests/instance_restart/instance_restart.test.o $(LAMBDA_LIBSHARED)
g++ $(CFLAGS) tests/instance_restart/instance_restart.test.o $(LAMBDA_LIBSHARED) $(EXTERNAL_LIBS) $(LINK_SYSTEM_LIBS) -o $(TEST_INSTANCE_RESTART_TARGET)

tests/instance_restart/instance_restart.test.o: tests/instance_restart/instance_restart.test.cpp
g++ -c $(CFLAGS) tests/instance_restart/instance_restart.test.cpp -o tests/instance_restart/instance_restart.test.o
1 change: 1 addition & 0 deletions tests/tests.mk
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ include tests/tcp/tcp.test.mk
include tests/vfs/vfs.test.mk
include tests/cookie/cookie.test.mk
include tests/headers/headers.test.mk
include tests/instance_restart/instance_restart.test.mk

0 comments on commit 1fad21f

Please sign in to comment.