Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/envoy/server/lifecycle_notifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ class ServerLifecycleNotifier {
*/
PostInit,

/**
* All workers have started.
*/
WorkerStarted,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not used? If this is needed WorkersStarted

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. My preference would be to not make prod changes like this just for tests. If you need synchronization hooks can you use https://github.com/envoyproxy/envoy/blob/master/source/server/listener_hooks.h instead? Thank you.

/wait


/**
* The server instance is being shutdown and the dispatcher is about to exit.
* This provides listeners a last chance to run a callback on the main dispatcher.
Expand Down
3 changes: 2 additions & 1 deletion include/envoy/server/listener_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,9 @@ class ListenerManager {
/**
* Start all workers accepting new connections on all added listeners.
* @param guard_dog supplies the guard dog to use for thread watching.
* @param callback supplies the callback to complete server initialization.
*/
virtual void startWorkers(GuardDog& guard_dog) PURE;
virtual void startWorkers(GuardDog& guard_dog, std::function<void()> callback) PURE;

/**
* Stop all listeners from accepting new connections without actually removing any of them. This
Expand Down
15 changes: 9 additions & 6 deletions source/server/listener_manager_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,7 @@ bool ListenerManagerImpl::removeListenerInternal(const std::string& name,
return true;
}

void ListenerManagerImpl::startWorkers(GuardDog& guard_dog) {
void ListenerManagerImpl::startWorkers(GuardDog& guard_dog, std::function<void()> callback) {
ENVOY_LOG(info, "all dependencies initialized. starting workers");
ASSERT(!workers_started_);
workers_started_ = true;
Expand All @@ -899,11 +899,13 @@ void ListenerManagerImpl::startWorkers(GuardDog& guard_dog) {
ENVOY_LOG(debug, "starting worker {}", i);
ASSERT(warming_listeners_.empty());
for (const auto& listener : active_listeners_) {
addListenerToWorker(*worker, absl::nullopt, *listener, [this, listeners_pending_init]() {
if (--(*listeners_pending_init) == 0) {
stats_.workers_started_.set(1);
}
});
addListenerToWorker(*worker, absl::nullopt, *listener,
[this, listeners_pending_init, callback]() {
if (--(*listeners_pending_init) == 0) {
stats_.workers_started_.set(1);
callback();
}
});
}
worker->start(guard_dog);
if (enable_dispatcher_stats_) {
Expand All @@ -913,6 +915,7 @@ void ListenerManagerImpl::startWorkers(GuardDog& guard_dog) {
}
if (active_listeners_.empty()) {
stats_.workers_started_.set(1);
callback();
}
}

Expand Down
2 changes: 1 addition & 1 deletion source/server/listener_manager_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ class ListenerManagerImpl : public ListenerManager, Logger::Loggable<Logger::Id:
listeners(ListenerState state = ListenerState::ACTIVE) override;
uint64_t numConnections() const override;
bool removeListener(const std::string& listener_name) override;
void startWorkers(GuardDog& guard_dog) override;
void startWorkers(GuardDog& guard_dog, std::function<void()> callback) override;
void stopListeners(StopListenersType stop_listeners_type) override;
void stopWorkers() override;
void beginListenerUpdate() override { error_state_tracker_.clear(); }
Expand Down
37 changes: 27 additions & 10 deletions source/server/server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -606,15 +606,22 @@ void InstanceImpl::onRuntimeReady() {
}

void InstanceImpl::startWorkers() {
listener_manager_->startWorkers(*worker_guard_dog_);
initialization_timer_->complete();
// Update server stats as soon as initialization is done.
updateServerStats();
workers_started_ = true;
// At this point we are ready to take traffic and all listening ports are up. Notify our parent
// if applicable that they can stop listening and drain.
restarter_.drainParentListeners();
drain_manager_->startParentShutdownSequence();
// The callback will be called after workers are started.
listener_manager_->startWorkers(*worker_guard_dog_, [this]() {
if (isShutdown()) {
return;
}
Comment on lines +614 to +616

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have test coverage of this case? (Put an ASSERT in there and see if it's hit or look at coverage report)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added test for this in the new commit.


initialization_timer_->complete();
// Update server stats as soon as initialization is done.
updateServerStats();
workers_started_ = true;
notifyCallbacksForStage(Stage::WorkerStarted);
// At this point we are ready to take traffic and all listening ports are up. Notify our
// parent if applicable that they can stop listening and drain.
restarter_.drainParentListeners();
drain_manager_->startParentShutdownSequence();
});
}

Runtime::LoaderPtr InstanceUtil::createRuntime(Instance& server,
Expand Down Expand Up @@ -710,6 +717,11 @@ void InstanceImpl::run() {
// startup (see RunHelperTest in server_test.cc).
const auto run_helper = RunHelper(*this, options_, *dispatcher_, clusterManager(),
access_log_manager_, init_manager_, overloadManager(), [this] {
if (!startup_) {
notifyCallbacksForStage(Stage::Startup);
startup_ = true;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain these changes? It's not clear to my why they were made. Please add more comments both here and below if they are necessary.

@caitong93 caitong93 Dec 14, 2020

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ensures Startup notifications to be sent first. Otherwise at LifecycleNotifications test , the notification order will be PostInit, WorkerStarted, Startup(because in static configuration, post_init_cb will be called immediately , before main thread dispatcher start), and deadlock will happen.(because we block callback at WorkerStarted stage)


notifyCallbacksForStage(Stage::PostInit);
startWorkers();
});
Expand All @@ -718,7 +730,12 @@ void InstanceImpl::run() {
ENVOY_LOG(info, "starting main dispatch loop");
auto watchdog = main_thread_guard_dog_->createWatchDog(api_->threadFactory().currentThreadId(),
"main_thread", *dispatcher_);
dispatcher_->post([this] { notifyCallbacksForStage(Stage::Startup); });
dispatcher_->post([this] {
if (!startup_) {
notifyCallbacksForStage(Stage::Startup);
startup_ = true;
}
});
dispatcher_->run(Event::Dispatcher::RunType::Block);
ENVOY_LOG(info, "main dispatch loop exited");
main_thread_guard_dog_->stopWatching(watchdog);
Expand Down
3 changes: 3 additions & 0 deletions source/server/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,9 @@ class InstanceImpl final : Logger::Loggable<Logger::Id::main>,
LifecycleCallbackHandle(std::list<T>& callbacks, T& callback)
: RaiiListElement<T>(callbacks, callback) {}
};

// startup_ is true means Startup notifications have been called.
bool startup_{};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this up into the variables section. Also startup_lifecycle_event_raised_ or something like that?

};

// Local implementation of Stats::MetricSnapshot used to flush metrics to sinks. We could
Expand Down
2 changes: 1 addition & 1 deletion test/mocks/server/listener_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class MockListenerManager : public ListenerManager {
(ListenerState state));
MOCK_METHOD(uint64_t, numConnections, (), (const));
MOCK_METHOD(bool, removeListener, (const std::string& listener_name));
MOCK_METHOD(void, startWorkers, (GuardDog & guard_dog));
MOCK_METHOD(void, startWorkers, (GuardDog & guard_dog, std::function<void()> callback));
MOCK_METHOD(void, stopListeners, (StopListenersType listeners_type));
MOCK_METHOD(void, stopWorkers, ());
MOCK_METHOD(void, beginListenerUpdate, ());
Expand Down
Loading