Skip to content

macOS launchctl Service Dependency Configuration in Practice: Taking Kafka's Dependency on Zookeeper as an Example ​

Schematic diagram of macOS launchctl service dependency configuration

Overview ​

Use in a macOS environment launchctl When managing services, we often encounter Service dependency the problem.

with Kafka For example: Kafka must depend on Zookeeper The service has already started successfully; otherwise, Kafka would fail to start because it cannot connect to Zookeeper.

If directly through launchctl Configure both services to start on boot. Since the startup order cannot be controlled, the following situation is very likely to occur:

Zookeeper has not started yet → Kafka attempts to start → Failed to connect to Zookeeper → Kafka failed to start ❌

This article will demonstrate how to use launchctl the plist configuration, so that Kafka at startup Wait for Zookeeper to be ready before starting., fundamentally solving the boot order problem.

Implementation plan ​

Core configuration items ​

at launchd In the plist configuration, service dependencies are implemented through the following two key configurations:

Configuration itemEffect
KeepAlive+OtherJobEnabledSpecify the Label of the target service that the current service depends on. The current service will remain running only when the target service is enabled.
AfterExplicitly specify which services the current service starts after (startup order control)

When the two are used together, it can ensure:

  • Startup order: Start the dependent service (Zookeeper) first.

  • runtime dependency: When a dependent service exits abnormally, the current service (Kafka) will also stop automatically (optional behavior)

1. Zookeeper Service Definition ​

Zookeeper, as a service that is depended on, does not require special configuration; simply define it in the standard way:

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Description</key>
        Zookeeper - is an open-source distributed coordination service that provides efficient and reliable coordination capabilities for distributed applications. It was originally developed by Yahoo and later became a top-level project of the Apache Software Foundation.
        <key>Disabled</key>
        <true/>
        <key>KeepAlive</key>
        <true/>
        <key>Label</key>
        <string>apache.org.zookeeper</string>
        <key>ProcessType</key>
        <string>Background</string>
        <key>ProgramArguments</key>
        <array>
            <string>/usr/local/opt/kafka/bin/zookeeper-server-start.sh</string>
            <string>/usr/local/opt/kafka/config/zookeeper.properties</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>StandardErrorPath</key>
        <string>/usr/local/var/log/zookeeper.log</string>
        <key>StandardOutPath</key>
        <string>/usr/local/var/log/zookeeper.log</string>
        <key>Version</key>
        <string>v3.8.4</string>
    </dict>
</plist>

2. Kafka Service Definition (with dependency configuration) ​

The configuration of Kafka services is the core of this article, with the focus on KeepAlive and After Field:

xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Description</key>
        Kafka - is an open-source distributed event streaming platform used by thousands of companies for high-performance data pipelines, streaming analytics, data integration, and mission-critical applications.
        <key>Disabled</key>
        <true/>
        <key>KeepAlive</key>
        <dict>
            <key>OtherJobEnabled</key>
            <string>apache.org.zookeeper</string>
        </dict>
        <key>After</key>
        <array>
            <string>apache.org.zookeeper</string>
        </array>
        <key>Label</key>
        <string>apache.org.kafka</string>
        <key>ProcessType</key>
        <string>Background</string>
        <key>ProgramArguments</key>
        <array>
            <string>/usr/local/opt/kafka/bin/kafka-server-start.sh</string>
            <string>/usr/local/opt/kafka/config/server.properties</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
        <key>StandardErrorPath</key>
        <string>/usr/local/var/log/kafka.log</string>
        <key>StandardOutPath</key>
        <string>/usr/local/var/log/kafka.log</string>
        <key>Version</key>
        <string>v3.9.0</string>
    </dict>
</plist>

Dependency Configuration Explained ​

xml
<key>KeepAlive</key>
<dict>
    <key>OtherJobEnabled</key>
    <string>apache.org.zookeeper</string>
</dict>
<key>After</key>
<array>
    <string>apache.org.zookeeper</string>
</array>
fieldvalueMeaning
KeepAlive OtherJobEnabledapache.org.zookeeperKafka will check whether the Zookeeper service is in enabled status; Kafka will keep running only when Zookeeper is enabled
After[apache.org.zookeeper]Clearly inform launchd: Kafka must be started after ZooKeeper to ensure the startup order.

Comparison: no dependencies vs with dependencies

Dependency-free configuration (conventional method):

xml
<key>KeepAlive</key>
<true/>

Under this configuration, Kafka does not check the status of any external services. During boot, it may start at the same time as Zookeeper or before Zookeeper, resulting in startup failure.

With dependency configuration (the method in this article):

xml
<key>KeepAlive</key>
<dict>
    <key>OtherJobEnabled</key>
    <string>apache.org.zookeeper</string>
</dict>
<key>After</key>
<array>
    <string>apache.org.zookeeper</string>
</array>

Kafka will wait for ZooKeeper to start and become available before starting itself, completely solving the startup order issue.

3. Loading service ​

After configuration is complete, run the following command to load the service:

bash
# Load the Kafka service (same for Zookeeper)
launchctl load ~/Library/LaunchAgents/apache.org.kafka.plist

# Or use bootstrap (recommended for macOS 10.10+)
launchctl bootstrap gui/$UID ~/Library/LaunchAgents/apache.org.kafka.plist

4. Verify the effect ​

bash
# Check the Zookeeper service status.
launchctl print gui/$UID/apache.org.zookeeper

# View Kafka service status (you can see the dependencies)
launchctl print gui/$UID/apache.org.kafka

# View service runtime logs
tail -f /usr/local/var/log/zookeeper.log
tail -f /usr/local/var/log/kafka.log

After the system restarts,launchd will start in the following order:

1. Zookeeper started ✅
2. Zookeeper status changed to enabled
3. Kafka detected that Zookeeper is ready
4. Kafka startup ✅

Extension: Other common service dependency scenarios ​

SceneDependency relationshipConfiguration method
Web services + databaseNginx depends on MySQLOtherJobEnabled→com.mysql.mysqld
Message Queue + StorageRabbitMQ depends on PostgreSQLOtherJobEnabled → org.postgresql.postgres
Monitoring tool + monitored servicePrometheus relies on Node ExporterOtherJobEnabled→io.prometheus.node_exporter
Microservice call chainService B depends on Service ASame as above, progressing step by step.

Precautions ​

  • plist file location: This example uses a user-level service, and the plist is stored in ~/Library/LaunchAgents/. If it is a system-level service, it needs to be placed in /Library/LaunchDaemons/ and use sudo Loading.

  • Disabled field: in the example Disabled for true, indicating that the service is disabled by default. You can enable it with the following command:

bash
launchctl enable gui/$UID/apache.org.kafka
  • circular dependency Avoid a circular dependency where A depends on B and B depends on A, which will cause the service to fail to start normally.

  • Dependent service Label must be accurate:OtherJobEnabled and After The Label filled in must be exactly the same as the Label of the dependent service.

Summary ​

  • on macOS via launchctl Managing service dependencies is fundamentally about configuration.KeepAlive+OtherJobEnabled and After Combination.

  • OtherJobEnabled Specify the Label of the target service to depend on, ensuring that the current service remains running only when the target service is enabled.

  • After Control the startup order to ensure that dependent services start first.

  • Through this solution, the startup order problem of services such as Kafka depending on Zookeeper can be perfectly solved.

Further reading ​

Last updated on11/07/2026, 02:16 PM
@fishfinal | @fishfinals | [email protected]