Skip to content

Commit

Permalink
[#555] Add c++ health monitoring example
Browse files Browse the repository at this point in the history
  • Loading branch information
elfenpiff committed Dec 19, 2024
1 parent fcde364 commit 2dda328
Show file tree
Hide file tree
Showing 10 changed files with 508 additions and 1 deletion.
1 change: 1 addition & 0 deletions examples/cxx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ add_subdirectory(domains)
add_subdirectory(event)
add_subdirectory(event_multiplexing)
add_subdirectory(event_based_communication)
add_subdirectory(health_monitoring)
add_subdirectory(publish_subscribe)
add_subdirectory(publish_subscribe_dynamic_data)
add_subdirectory(publish_subscribe_with_user_header)
Expand Down
61 changes: 61 additions & 0 deletions examples/cxx/health_monitoring/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Copyright (c) 2024 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache Software License 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
# which is available at https://opensource.org/licenses/MIT.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT

load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")

cc_binary(
name = "example_cxx_health_monitoring_central_daemon",
srcs = [
"src/central_daemon.cpp",
"src/pubsub_event.hpp"
],
deps = [
"@iceoryx//:iceoryx_hoofs",
"//:iceoryx2-cxx-static",
],
)

cc_binary(
name = "example_cxx_health_monitoring_publisher_1",
srcs = [
"src/publisher_1.cpp",
"src/pubsub_event.hpp"
],
deps = [
"@iceoryx//:iceoryx_hoofs",
"//:iceoryx2-cxx-static",
],
)

cc_binary(
name = "example_cxx_health_monitoring_publisher_2",
srcs = [
"src/publisher_2.cpp",
"src/pubsub_event.hpp"
],
deps = [
"@iceoryx//:iceoryx_hoofs",
"//:iceoryx2-cxx-static",
],
)

cc_binary(
name = "example_cxx_health_monitoring_subscriber",
srcs = [
"src/subscriber.cpp",
"src/pubsub_event.hpp"
],
deps = [
"@iceoryx//:iceoryx_hoofs",
"//:iceoryx2-cxx-static",
],
)
28 changes: 28 additions & 0 deletions examples/cxx/health_monitoring/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright (c) 2024 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache Software License 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
# which is available at https://opensource.org/licenses/MIT.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT

cmake_minimum_required(VERSION 3.22)
project(example_cxx_health_monitoring LANGUAGES CXX)

find_package(iceoryx2-cxx 0.4.1 REQUIRED)

add_executable(example_cxx_health_monitoring_central_daemon src/central_daemon.cpp)
target_link_libraries(example_cxx_health_monitoring_central_daemon iceoryx2-cxx::static-lib-cxx)

add_executable(example_cxx_health_monitoring_publisher_1 src/publisher_1.cpp)
target_link_libraries(example_cxx_health_monitoring_publisher_1 iceoryx2-cxx::static-lib-cxx)

add_executable(example_cxx_health_monitoring_publisher_2 src/publisher_2.cpp)
target_link_libraries(example_cxx_health_monitoring_publisher_2 iceoryx2-cxx::static-lib-cxx)

add_executable(example_cxx_health_monitoring_subscriber src/subscriber.cpp)
target_link_libraries(example_cxx_health_monitoring_subscriber iceoryx2-cxx::static-lib-cxx)
1 change: 1 addition & 0 deletions examples/cxx/health_monitoring/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

106 changes: 106 additions & 0 deletions examples/cxx/health_monitoring/src/central_daemon.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright (c) 2024 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available under the
// terms of the Apache Software License 2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
// which is available at https://opensource.org/licenses/MIT.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

#include <iostream>

#include "iox/duration.hpp"
#include "iox2/node.hpp"
#include "iox2/service_name.hpp"
#include "iox2/service_type.hpp"
#include "iox2/waitset.hpp"
#include "pubsub_event.hpp"

using namespace iox2;

constexpr iox::units::Duration CYCLE_TIME = iox::units::Duration::fromMilliseconds(100);

void find_and_cleanup_dead_nodes();

auto main() -> int {
auto service_name_1 = ServiceName::create("service_1").expect("");
auto service_name_2 = ServiceName::create("service_2").expect("");

auto node = NodeBuilder()
.name(NodeName::create("central daemon").expect(""))
.create<ServiceType::Ipc>()
.expect("successful node creation");

// The central daemon is responsible to create all services before hand and the other processes
// just open the communication resources and start communicating.
auto service_pubsub_1 = node.service_builder(service_name_1)
.publish_subscribe<uint64_t>()
// We use here open_or_create so that, in case of a crash of the central daemon, it can
// be restarted.
.open_or_create()
.expect("successful service creation/opening");

auto service_event_1 = node.service_builder(service_name_1)
.event()
// Whenever a new notifier is created the PublisherConnected event is emitted. this makes
// sense since in this example a notifier is always created after a new publisher was
// created.
// The task of the notifier/event is it to inform and wake up other processes when
// certain system event have happened.
.notifier_created_event(iox::into<EventId>(PubSubEvent::PublisherConnected))
.notifier_dropped_event(iox::into<EventId>(PubSubEvent::PublisherDisconnected))
// This event is emitted when either the central daemon or a decentralized process
// detects a dead node and cleaned up all of its stale resources succesfully.
.notifier_dead_event(iox::into<EventId>(PubSubEvent::ProcessDied))
.open_or_create()
.expect("successful service creation/opening");

auto service_pubsub_2 = node.service_builder(service_name_2)
.publish_subscribe<uint64_t>()
.open_or_create()
.expect("successful service creation/opening");

auto service_event_2 = node.service_builder(service_name_2)
.event()
.notifier_created_event(iox::into<EventId>(PubSubEvent::PublisherConnected))
.notifier_dropped_event(iox::into<EventId>(PubSubEvent::PublisherDisconnected))
.notifier_dead_event(iox::into<EventId>(PubSubEvent::ProcessDied))
.open_or_create()
.expect("successful service creation/opening");

auto waitset = WaitSetBuilder().create<ServiceType::Ipc>().expect("");
auto cycle_guard = waitset.attach_interval(CYCLE_TIME);

std::cout << "Central daemon up and running." << std::endl;
waitset
// The only task of our central daemon is it to monitor all running nodes and cleanup their
// resources if a process has died.
//
// Since we added the notifier_dead_event to the service, all listeners, that are waiting
// on a service where one participant has died, will be woken up and they receive
// the PubSubEvent::ProcessDied
.wait_and_process([](auto) {
find_and_cleanup_dead_nodes();
return CallbackProgression::Continue;
})
.expect("");

std::cout << "exit" << std::endl;

return 0;
}

void find_and_cleanup_dead_nodes() {
Node<ServiceType::Ipc>::list(Config::global_config(), [](auto node_state) {
node_state.dead([](auto view) {
std::cout << "detected dead node: ";
view.details().and_then([](auto details) { std::cout << details.name().to_string().c_str(); });
std::cout << std::endl;
view.remove_stale_resources().expect("");
});
return CallbackProgression::Continue;
}).expect("");
}
63 changes: 63 additions & 0 deletions examples/cxx/health_monitoring/src/publisher_1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (c) 2024 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available under the
// terms of the Apache Software License 2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
// which is available at https://opensource.org/licenses/MIT.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

#include "iox/duration.hpp"
#include "iox2/node.hpp"
#include "iox2/service_name.hpp"
#include "iox2/service_type.hpp"
#include "iox2/waitset.hpp"
#include "pubsub_event.hpp"

#include <iostream>

constexpr iox::units::Duration CYCLE_TIME = iox::units::Duration::fromMilliseconds(1000);

auto main() -> int {
using namespace iox2;
auto service_name = ServiceName::create("service_1").expect("");
auto node = NodeBuilder()
.name(NodeName::create("publisher 1").expect(""))
.create<ServiceType::Ipc>()
.expect("successful node creation");

auto service = open_service(node, service_name);

auto publisher = service.pubsub.publisher_builder().create().expect("");
auto notifier = service.event
.notifier_builder()
// we only want to notify the other side explicitly when we have sent a sample
// so we can define it as default event id
.default_event_id(iox::into<EventId>(PubSubEvent::SentSample))
.create()
.expect("");
auto counter = 0;

auto waitset = WaitSetBuilder().create<ServiceType::Ipc>().expect("");

// we only want to notify the other side explicitly when we have sent a sample
// so we can define it as default event id
auto cycle_guard = waitset.attach_interval(CYCLE_TIME);

waitset
.wait_and_process([&](auto) {
std::cout << service_name.to_string().c_str() << ": Send sample " << counter << " ..." << std::endl;
publisher.send_copy(counter).expect("");
notifier.notify().expect("");
counter += 1;
return CallbackProgression::Continue;
})
.expect("");

std::cout << "exit" << std::endl;

return 0;
}
63 changes: 63 additions & 0 deletions examples/cxx/health_monitoring/src/publisher_2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (c) 2024 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available under the
// terms of the Apache Software License 2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
// which is available at https://opensource.org/licenses/MIT.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

#include "iox/duration.hpp"
#include "iox2/node.hpp"
#include "iox2/service_name.hpp"
#include "iox2/service_type.hpp"
#include "iox2/waitset.hpp"
#include "pubsub_event.hpp"

#include <iostream>

constexpr iox::units::Duration CYCLE_TIME = iox::units::Duration::fromMilliseconds(1500);

auto main() -> int {
using namespace iox2;
auto service_name = ServiceName::create("service_2").expect("");
auto node = NodeBuilder()
.name(NodeName::create("publisher 2").expect(""))
.create<ServiceType::Ipc>()
.expect("successful node creation");

auto service = open_service(node, service_name);

auto publisher = service.pubsub.publisher_builder().create().expect("");
auto notifier = service.event
.notifier_builder()
// we only want to notify the other side explicitly when we have sent a sample
// so we can define it as default event id
.default_event_id(iox::into<EventId>(PubSubEvent::SentSample))
.create()
.expect("");
auto counter = 1000000; // NOLINT, magic number is fine in an example

auto waitset = WaitSetBuilder().create<ServiceType::Ipc>().expect("");

// we only want to notify the other side explicitly when we have sent a sample
// so we can define it as default event id
auto cycle_guard = waitset.attach_interval(CYCLE_TIME);

waitset
.wait_and_process([&](auto) {
std::cout << service_name.to_string().c_str() << ": Send sample " << counter << " ..." << std::endl;
publisher.send_copy(counter).expect("");
notifier.notify().expect("");
counter += 1;
return CallbackProgression::Continue;
})
.expect("");

std::cout << "exit" << std::endl;

return 0;
}
56 changes: 56 additions & 0 deletions examples/cxx/health_monitoring/src/pubsub_event.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) 2024 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available under the
// terms of the Apache Software License 2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
// which is available at https://opensource.org/licenses/MIT.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

#ifndef __EXAMPLE_HEALTH_MONITORING_PUBSUB_EVENT_HPP__
#define __EXAMPLE_HEALTH_MONITORING_PUBSUB_EVENT_HPP__

#include "iox/into.hpp"
#include "iox2/event_id.hpp"
#include "iox2/node.hpp"
#include "iox2/service_name.hpp"

#include <cstdint>

enum class PubSubEvent : uint8_t {
PublisherConnected = 0,
PublisherDisconnected = 1,
SubscriberConnected = 2,
SubscriberDisconnected = 3,
SentSample = 4,
ReceivedSample = 5,
SentHistory = 6,
ProcessDied = 7,
Unknown,
};

struct ServiceTuple {
iox2::PortFactoryEvent<iox2::ServiceType::Ipc> event;
iox2::PortFactoryPublishSubscribe<iox2::ServiceType::Ipc, uint64_t, void> pubsub;
};

inline auto open_service(const iox2::Node<iox2::ServiceType::Ipc>& node,
const iox2::ServiceName& service_name) -> ServiceTuple {
auto service_pubsub = node.service_builder(service_name).publish_subscribe<uint64_t>().open().expect("");
auto service_event = node.service_builder(service_name).event().open().expect("");

return { std::move(service_event), std::move(service_pubsub) };
}

namespace iox {
template <>
inline auto from<PubSubEvent, iox2::EventId>(const PubSubEvent value) noexcept -> iox2::EventId {
return iox2::EventId(static_cast<uint64_t>(value));
}
} // namespace iox


#endif
Loading

0 comments on commit 2dda328

Please sign in to comment.