Mikroteenused C++-s. Kujutlusvõime või reaalsus?

Mikroteenused C++-s. Kujutlusvõime või reaalsus?

Selles artiklis räägin, kuidas ma lõin mall (cookiecutter) ja seadistasin keskkonna REST API teenuse kirjutamiseks C++ keeles, kasutades dockeri/dockeri koostamist ja pakihaldurit conan.

Ühe hackathon'i ajal, kus ma osalesin tagaplaneerija arendajana, tekkis küsimus, millega kirjutada järgmine mikroteenus. Kõik, mis oli seni kirjutatud, oli minu ja minu kaaslase poolt kirjutatud Pythonis, kuna mu kolleeg oli selles valdkonnas spetsialist ja tegeles professionaalselt tagaplaneerimisega, samal ajal kui mina olin pigem sisseehitatud süsteemide arendaja, kes kirjutas see-eest suures ja kohutavas C++-s ja õppisin Pythonit lihtsalt ülikoolis.

Nii et meil oli ülesanne kirjutada kõrge koormusega teenus, mille peamiseks ülesanneks oli sisenevate andmete eelprotsessimine ja nende salvestamine andmebaasi. Ja pärast järgmist pausi pakkus mu kaaslane, kui C++ arendaja, et kirjutaksin teenuse C++-s. Argumenteerides, et nii on see kiiremini ja efektiivsemalt, ning üldiselt oleks žürii vaimustuses sellest, kuidas me suudame meeskonna ressursse juhtida. Mina ütlesin, et kunagi pole selliste asjadega C++-s tegelenud ja võiksin hõlpsasti jäävad 20+ tundi pühendada sobivate raamatukogude otsimisele, kompileerimisele ja linkimisele. Lühidalt öeldes, ma kartsin. Sellega olime nõus ja kirjutasime kõik rahulikult Pythonis.

Praegu, sunnitud isoleerimise ajal, otsustasin mõista, kuidas kirjutada teenuseid C++-s. Esimene asi, mida tuli teha, oli valida sobiv raamatukogu. Minu valik langes POCO, kuna see oli kirjutatud objektorienteeritud stiilis ning oskas ka kiidelda korraliku dokumentatsiooniga. Samuti tekkis küsimus, millist kogumise süsteemi valida. Seni olin töötanud ainult Visual Studio, IAR ja "puhta" makefile'iga. Ja ükski neist süsteemidest ei meeldinud mulle, kuna plaanisin kogu teenuse käivitamist docker-konteineris. Sel hetkel otsustasin uurida cmake'i ja huvitavat pakihaldurit conan. See pakihaldur võimaldas kõik sõltuvused ühte faili

conanfile.txt
[requires]
poco/1.9.3
libpq/11.5

[generators]
cmake

ja lihtsa käsu "conan install ." abil paigaldada vajalikud raamatukogud. Loomulikult tuli ka teha muudatusi

CMakeLists.txt

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

Pärast seda hakkasin otsima PostgreSQL-iga töötamise raamatukogu, kuna mul oli selle osas väike kogemus ning meie teenused töötasid Pythonis just selle raamatukoguga. Ja tead, mida ma avastasin? See on POCO-s olemas! Kuid conan ei tea, et see on POCO-s ja ei oska seda ehitada, hoidis repozitoorium vananenud konfiguratsioonifaili (ma olen juba sellest veast POCO loojaid teavitanud). See tähendab, et pean otsima teise raamatukogu.

Ja siis valisin vähem populaarse raamatukogu libpg. Ja mul vedas, see oli juba conan-is olemas ja isegi ehitati ja linkiti.

Järgmine samm oli teenuse шаблoni kirjutamine, mis oskab päringuid töödelda.
Me peame pärima meie klassi TemplateServerApp POCO::Util::ServerApplication-str ja ületama meetodi main.

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 &)
{
    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;
}

Meetodis main peame määrama parameetrid: port, lõimede arv ja vahejärjekorra suurus. Ja kõige tähtsam, peame määrama sissetulevate päringute töötleja. Seda tehakse fabrika loomise kaudu

TemplateRequestHandlerFactory

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

Minu puhul loob see iga kord ühe ja sama töötleja — TemplateServerAppHandler. Just siin saame me paigutada oma äriloogika.

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 klassi malli PostgreSQL-iga töötamiseks. Lihtsa SQL-i, näiteks tabeli loomise, täitmiseks on meetod ExecuteSQL(). Tüüpiliste küsitluste või andmete saamiseks tuleb kasutada ühendust, mis saadakse kaudu GetConnection() ja kasutada libpg API-d. (Võimalik, et ma parandada selle ebaõigluse hiljem).

Database

#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 andmebaasi ühenduse parameetrid saadakse keskkonnast, seega peate looma ja seadistama ka faili .env

.env

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

Saate kogu koodi vaadata GitHubis.

Mikroteenused C++-s. Kujutlusvõime või reaalsus?

Ja on saabunud viimane etapp dockerfile ja docker-compose.yml kirjutamisel. Ütlen ausalt, see võttis suure osa ajast, ja mitte ainult seetõttu, et ma olen algaja, kes peab iga kord teeki uuesti kompileerima, vaid ka loomulike takistuste tõttu conaniga. Näiteks, et conan allalaadiks, installiks ja buildiks vajalikud sõltuvused, ei piisa vaid 'conan install .' käsust; tal on samuti vaja edastada parameeter -s compiler.libcxx=libstdc++11, vastasel juhul riskite saada hulga vigu teie rakenduse linkimise etapis. Veetsin selle vea tõttu mitmeid tunde, ja loodan, et see artikkel aitab teistel inimestel selle probleemi kiiremini lahendada.

Seejärel, pärast docker-compose.yml kirjutamist, soovitas mu sõber mulle lisada toe cookiecutter ja nüüd saate endale täisfunktsionaalse malli REST API teenuse jaoks C++-is, seadistatud keskkonnaga, ja käivitatud PostgreSQL-i, lihtsalt tippides terminali "cookiecutter https://github.com/KovalevVasiliy/cpp_rest_api_template.git". Ja siis "docker-compose up —build".

Loodan, et see mall aitab algajatel nende keerulisel teel REST API rakenduste arendamisel suures ja võimsas, kuid nii rängas keeles nagu C++.
Samuti soovitan tungivalt lugeda seda seda artiklit. Selles selgitatakse lähemalt, kuidas töötada POCO-ga ja kirjutada oma REST API teenus.

Allikas: habr.com

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster