Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When ulfius starts in a docker container it exits 0 #273

Open
joegasewicz opened this issue Jun 27, 2024 · 6 comments
Open

When ulfius starts in a docker container it exits 0 #273

joegasewicz opened this issue Jun 27, 2024 · 6 comments
Labels

Comments

@joegasewicz
Copy link

Describe the issue
I want to dockerize an app that uses ulfius, it builds and runs successfully but then exists 0 straight away
For example:

docker run -p 8005:8005 bandnoticeboard/nottoboard:forestmq-0.1.2
Starting server on http://localhost:8005

Process finished with exit code 0

To Reproduce
You can pull down the code from https://github.com/joegasewicz/forestmq

Expected behavior
I expect the ulfius server to persist when run inside a docker container

System (please complete the following information):

@joegasewicz joegasewicz changed the title ulfius starts in a docker exits 0 When ulfius starts in a docker container it exits 0 Jun 27, 2024
@joegasewicz
Copy link
Author

I think I need to set the host, is this done via the ulfius_init_instance functions's bind_address parameter?

@babelouest
Copy link
Owner

Hello,

It's hard to say without the server source code, which doesn't seem to be hosted in the repo you mention.

But my first guess is that you don't make your server waiting right after starting the ulfius endpoint. Ulfius webserver is executed in a non blocking thread so your server can do other things.

In the example programs, I usually use getchar() to keep the program running but that's not a good method for a server.

You can search for "daemon programming c" to get some examples.

@joegasewicz
Copy link
Author

joegasewicz commented Jun 27, 2024

Here's the current server code:

#include <stdio.h>
#include <stdlib.h>
#include <ulfius.h>
#include <jansson.h>
#include <string.h>
#include <stdbool.h>
#include <netinet/in.h>
#include "tcp.h"
#include "queue.h"
#include "config.h"


static int callback_consumer(const struct _u_request *request,
    struct _u_response *response, void *queue)
{
    JSON_INDENT(4);
    const FMQ_Queue *q = (FMQ_Queue*)queue;
    const FMQ_QNode *node = FMQ_Queue_dequeue((FMQ_Queue*)queue);
    if (node == NULL)
    {
        FMQ_LOGGER(q->log_level ,"Queue is empty\n");
        ulfius_set_json_body_response(response, 204, json_pack("{s:s}", "message", NULL));
        return U_CALLBACK_CONTINUE;
    }
    const FMQ_Data *dataPtr = (FMQ_Data*)node->data;
    FMQ_LOGGER(q->log_level, "Successfully dequeued message for consumer\n");
    ulfius_set_json_body_response(response, 200, json_pack("{s:s}", "message", dataPtr->message));
    free((FMQ_Data*)node->data);
    free((FMQ_QNode*)node);
    return U_CALLBACK_CONTINUE;
}

static int callback_provider(const struct _u_request *request,
    struct _u_response *response, void *queue)
{
    const FMQ_Queue *q = (FMQ_Queue*)queue;
    JSON_INDENT(4);
    json_t *json_body = ulfius_get_json_body_request(request, NULL);
    const char *message = json_string_value(json_object_get(json_body, "message"));
    bool destroy = json_boolean_value(json_object_get(json_body, "destroy"));
    if (destroy) {
        FMQ_QUEUE_destroy((FMQ_Queue*)queue);
        FMQ_LOGGER(q->log_level, "Successfully destroyed queue\n");
        ulfius_set_json_body_response(response, 200, json_pack("{s:s}", "message", message));
        return U_CALLBACK_CONTINUE;
    }
    FMQ_LOGGER(q->log_level, "Received: %s\n", message);
    FMQ_Data *data = (FMQ_Data*)malloc(sizeof(FMQ_Queue));
    data->message = malloc(sizeof(char) * q->msg_size);
    strcpy(data->message, message);
    FMQ_Queue_enqueue((FMQ_Queue*)queue, data);

    ulfius_set_json_body_response(response, 200, json_pack("{s:s}", "message", message));

    json_decref(json_body);
    return U_CALLBACK_CONTINUE;
}

static int start_server(FMQ_TCP *tcp)
{
    struct _u_instance instance;

    if (ulfius_init_instance(&instance, tcp->port, NULL, NULL) != U_OK)
    {
        fprintf(stderr, "Error starting ulfius server\n");
        exit(EXIT_FAILURE);
    }

    ulfius_add_endpoint_by_val(&instance, "POST", "/consumer", NULL, 0, &callback_consumer, tcp->queue);
    ulfius_add_endpoint_by_val(&instance, "POST", "/provider", NULL, 0, &callback_provider, tcp->queue);

    if (ulfius_start_framework(&instance) == U_OK)
    {
        printf("Starting server on http://localhost:%d\n", instance.port);
        getchar();
    }
    else
    {
        fprintf(stderr, "Error starting server...\n");
        printf("Error: \n\t- Tip: Check that port %d is not busy\n", tcp->port);
    }
    FMQ_LOGGER(tcp->log_level, "Stopping server \n");

    ulfius_stop_framework(&instance);
    ulfius_clean_instance(&instance);
    return 0;
}

FMQ_TCP *FMQ_TCP_new(FMQ_Queue *queue, const u_int16_t port, const int8_t log_level)
{
    FMQ_TCP *tcp = (FMQ_TCP*)malloc(sizeof(FMQ_TCP));
    tcp->queue = queue;
    tcp->start = start_server;
    tcp->port = port;
    tcp->log_level = log_level;
    return tcp;
}

This is the Dockerfile

FROM --platform=linux/amd64 ubuntu:22.04

WORKDIR /forestmq

COPY . .

ENV APPLE = 0
ENV UNIX = 1

RUN apt update
RUN apt install -y libulfius-dev uwsc
RUN apt install -y libmicrohttpd-dev
RUN apt install -y libjansson-dev
RUN apt install -y libcurl4-gnutls-dev
RUN apt install -y libgnutls28-dev
RUN apt install -y libgcrypt20-dev
RUN apt install -y libsystemd-dev
RUN apt install -y pkg-config
RUN apt install -y cmake

#RUN mkdir build
RUN cmake -S . -B build
RUN make -C build

EXPOSE 8005

CMD ["./build/forest_mq"]

@joegasewicz
Copy link
Author

joegasewicz commented Jun 27, 2024

@babelouest
Yes I am blocking the main thread with getchar() as per your example -

 if (ulfius_start_framework(&instance) == U_OK)
    {
        printf("Starting server on http://localhost:%d\n", instance.port);
        getchar();
    }

Is it possible to set the host, for example to 0.0.0.0 ?

@babelouest
Copy link
Owner

@babelouest Is it possible to set the host, for example to 0.0.0.0 ?

I'm not sure what tout expect if you set the host, but setting the bind_address won't change the server exiting right after starting ulfius webserver.

Your problem doesn't seem to be how to use ulfius but how to program a daemon in C.

My best guess is to look for examples, to help you build a program running in docker.

@joegasewicz
Copy link
Author

@babelouest ok thanks for the advice.

I got it working using -it arg to start the container in the interactive mode... might help someone else with this issue.
e.g

docker run -it -p 8005:8005 $(IMG_NAME)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants