Mikroteenused C++ keeles. Väljamõeldis või reaalsus?

Mikroteenused C++ keeles. Väljamõeldis või reaalsus?

Selles artiklis räägin sellest, kuidas ma lõin malli (cookiecutter) ja seadistasin C++ keeles REST API teenuse kirjutamise keskkonna, kasutades docker/docker-compose ja conan paketihaldurit.

Järgmisel häkatonil, kus taustaarendajana osalesin, tekkis küsimus, mida järgmise mikroteenuse kirjutamiseks kasutada. Kõik, mis seni kirjutatud on, on minu ja minu kirjutatud seltsimees Pythonis, kuna mu kolleeg oli selles valdkonnas asjatundja ja arendas professionaalselt taustaprogramme, samal ajal kui mina olin üldiselt manustatud süsteemide arendaja ja kirjutasin suurepärases ja kohutavas C++ keeles ning õppisin just ülikoolis Pythoni ära.

Niisiis seisis meie ees ülesanne kirjutada suure koormusega teenus, mille põhiülesanne oli sinna saabuvate andmete eeltöötlemine ja andmebaasi kirjutamine. Ja pärast järjekordset suitsupausi soovitas sõber mul kui C++ arendajal see teenus professionaale kasutades kirjutada. Väidetavalt on see kiirem, produktiivsem ja üldiselt on žüriil hea meel, kuidas me teame, kuidas meeskonna ressursse hallata. Mille peale vastasin, et ma pole kunagi C++-s selliseid asju teinud ja saan ülejäänud 20+ tundi vabalt pühendada sobivate teekide otsimisele, koostamisele ja linkimisele. Lihtsamalt öeldes läksin tühjaks. Just selle otsustasime ja Pythonis kõik rahulikult lõpule viisime.

Nüüd, sunnitud eneseisolatsiooni ajal, otsustasin välja mõelda, kuidas C++ keeles teenuseid kirjutada. Esimese asjana tuli otsustada sobiv raamatukogu. Minu valik langes peale POCO, kuna see oli kirjutatud objektorienteeritud stiilis ja sellel oli ka tavaline dokumentatsioon. Samuti tekkis küsimus koostesüsteemi valiku kohta. Seni olen töötanud ainult Visual Studio, IAR-i ja tühjade makefailidega. Ja ükski neist süsteemidest ei meeldinud mulle, kuna plaanisin kogu teenust käitada dokkimiskonteineris. Siis otsustasin proovida välja mõelda cmake ja huvitava paketihalduri Conan. See paketihaldur võimaldas teil registreerida kõik sõltuvused ühes failis

conanfile.txt
[nõuab]poco/1.9.3
libpq/11.5

[generaatorid] cmake

ja lihtsa käsuga "conan install." installige vajalikud raamatukogud. Loomulikult oli vaja ka muudatusi teha

CMakeLists.txt

include(build/conanbuildinfo.cmake)
conan_basic_setup()
target_link_libraries(<target_name> ${CONAN_LIBS})

Pärast seda hakkasin otsima teeki, millega PostgreSQL-iga töötada, kuna sellega oli mul vähe töökogemust ja see oli ka see, millega meie Pythoni teenused suhtlesid. Ja kas sa tead, mida ma õppisin? See on POCO-s! Kuid conan ei tea, et see on POCO-s, ega tea, kuidas seda ehitada; hoidlas on aegunud konfiguratsioonifail (sellest veast olen juba kirjutanud POCO loojatele). See tähendab, et peate otsima teise raamatukogu.

Ja siis langes minu valik vähem populaarsele raamatukogule libpg. Ja mul vedas uskumatult, see oli juba valmis ja seda isegi hakati kokku panema ja kokku panema.

Järgmine samm oli teenusemalli kirjutamine, mis suudab taotlusi töödelda.
Peame pärima oma klassi TemplateServerApp Poco::Util::ServerApplicationilt ja alistama põhimeetodi.

TemplateServerApp

#pragma once

#include <string>
#include <vector>
#include <Poco/Util/ServerApplication.h>

class TemplateServerApp : public Poco::Util::ServerApplication
{
    protected:
        int main(const std::vector<std::string> &);
};

int TemplateServerApp::main(const vector<string> &)
{
    HTTPServerParams* pParams = new HTTPServerParams;

    pParams->setMaxQueued(100);
    pParams->setMaxThreads(16);

    HTTPServer s(new TemplateRequestHandlerFactory, ServerSocket(8000), pParams);

    s.start();
    cerr << "Server started" << endl;

    waitForTerminationRequest();  // wait for CTRL-C or kill

    cerr << "Shutting down..." << endl;
    s.stop();

    return Application::EXIT_OK;
}

Põhimeetodis peame määrama parameetrid: port, lõimede arv ja järjekorra suurus. Ja mis kõige tähtsam, peate määrama sissetulevate päringute töötleja. Seda tehakse tehase loomisega

TemplateRequestHandlerFactory

class TemplateRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
    virtual HTTPRequestHandler* createRequestHandler(const HTTPServerRequest & request)
    {
        return new TemplateServerAppHandler;
    }
};

Minu puhul loob see lihtsalt iga kord sama töötleja – TemplateServerAppHandler. Siin saame oma äriloogika paigutada.

TemplateServerAppHandler

class TemplateServerAppHandler : public HTTPRequestHandler
{
public:
    void handleRequest(HTTPServerRequest &req, HTTPServerResponse &resp)
    {
        URI uri(req.getURI());
        string method = req.getMethod();

        cerr << "URI: " << uri.toString() << endl;
        cerr << "Method: " << req.getMethod() << endl;

        StringTokenizer tokenizer(uri.getPath(), "/", StringTokenizer::TOK_TRIM);
        HTMLForm form(req,req.stream());

        if(!method.compare("POST"))
        {
            cerr << "POST" << endl;
        }
        else if(!method.compare("PUT"))
        {
            cerr << "PUT" << endl;
        }
        else if(!method.compare("DELETE"))
        {
            cerr << "DELETE" << endl;
        }

        resp.setStatus(HTTPResponse::HTTP_OK);
        resp.setContentType("application/json");
        ostream& out = resp.send();

        out << "{"hello":"heh"}" << endl;
        out.flush();
    }
};

Samuti lõin PostgreSQL-iga töötamiseks klassi malli. Lihtsa SQL-i tegemiseks, näiteks tabeli loomiseks, on olemas meetod ExecuteSQL(). Keerulisemate päringute või andmete otsimise jaoks peate looma ühenduse kaudu GetConnection() ja kasutage libpg API-t. (Ehk hiljem parandan selle ebaõigluse).

andmebaas

#pragma once

#include <memory>
#include <mutex>
#include <libpq-fe.h>

class Database
{
public:
    Database();
    std::shared_ptr<PGconn> GetConnection() const;
    bool ExecuteSQL(const std::string& sql);

private:
    void establish_connection();
    void LoadEnvVariables();

    std::string m_dbhost;
    int         m_dbport;
    std::string m_dbname;
    std::string m_dbuser;
    std::string m_dbpass;

    std::shared_ptr<PGconn>  m_connection;
};

Kõik andmebaasiga ühenduse loomise parameetrid on võetud keskkonnast, seega tuleb luua ja seadistada ka env fail

.env

DATABASE_NAME=template
DATABASE_USER=user
DATABASE_PASSWORD=password
DATABASE_HOST=postgres
DATABASE_PORT=5432

Kogu koodi näete aadressil github.

Mikroteenused C++ keeles. Väljamõeldis või reaalsus?

Ja nüüd tuleb dockerfile'i ja docker-compose.yml kirjutamise viimane etapp. Ausalt öeldes võttis see suurema osa ajast ja mitte ainult sellepärast, et ma olen noob, sest iga kord oli vaja raamatukogusid uuesti üles ehitada, vaid ka conani lõksude tõttu. Näiteks selleks, et conan saaks alla laadida, installida ja luua vajalikud sõltuvused, ei piisa ainult "conan install ." allalaadimisest, vaid peab edastama ka parameetri -s compiler.libcxx=libstdc++11, vastasel juhul võite oma rakenduse linkimise etapis saada hunniku vigu. Olen selle veaga mitu tundi ummikus olnud ja loodan, et see artikkel aitab teistel inimestel seda probleemi lühema ajaga lahendada.

Järgmiseks, pärast docker-compose.yml kirjutamist, lisasin sõbra nõuandel tuge küpsiselõikur ja nüüd saate endale kohandatud keskkonna ja installitud PostgreSQL-iga C++-s REST API teenuse täisväärtusliku malli, sisestades lihtsalt konsooli "cookiecutter". https://github.com/KovalevVasiliy/cpp_rest_api_template.git" Ja siis "docker-compose up -build".

Loodan, et see mall aitab algajaid nende raskel teel arendada REST API rakendusi suurepärases ja võimsas, kuid sellises kohmakas keeles nagu C++.
Samuti soovitan soojalt siit lugeda see artiklit. See selgitab üksikasjalikumalt, kuidas töötada POCO-ga ja kirjutada oma REST API teenus.

Allikas: www.habr.com

Lisa kommentaar