Միկրոծառայություններ C++-ում։ Գեղարվեստական, թե իրականություն.

Միկրոծառայություններ C++-ում։ Գեղարվեստական, թե իրականություն.

Այս հոդվածում ես կխոսեմ այն ​​մասին, թե ինչպես ստեղծեցի ձևանմուշ (cookiecutter) և ստեղծեցի միջավայր C++-ում REST API ծառայություն գրելու համար՝ օգտագործելով docker/docker-compose և conan փաթեթի կառավարիչը։

Հաջորդ հաքաթոնի ժամանակ, որին ես մասնակցում էի որպես backend-ի ծրագրավորող, հարց առաջացավ, թե ինչ օգտագործել հաջորդ միկրոսերվիսը գրելու համար։ Այն ամենը, ինչ գրվել է մինչ այժմ, գրել ենք իմ և իմ կողմից ընկեր Python-ում, քանի որ իմ գործընկերն այս ոլորտում փորձագետ էր և մասնագիտորեն մշակում էր backends, մինչդեռ ես ընդհանուր առմամբ ներդրված համակարգերի մշակող էի և գրում էի հիանալի ու սարսափելի C++-ով, իսկ ես հենց նոր սովորեցի Python համալսարանում:

Այսպիսով, մեր առջեւ խնդիր էր դրված գրել մեծ բեռնված ծառայություն, որի հիմնական խնդիրն էր նախապես մշակել դրան եկող տվյալները եւ գրել դրանք տվյալների բազայում։ Եվ հերթական ծխի ընդմիջումից հետո ընկերս առաջարկեց, որ ես՝ որպես C++ ծրագրավորող, գրեմ այս ծառայությունը՝ օգտագործելով պրոֆեսիոնալները։ Պնդելով սա այն է, որ դա կլինի ավելի արագ, ավելի արդյունավետ, և, ընդհանուր առմամբ, ժյուրին հիացած կլինի նրանով, թե ինչպես մենք գիտենք, թե ինչպես կառավարել թիմի ռեսուրսները: Ինչին ես պատասխանեցի, որ ես երբեք նման բաներ չեմ արել C++-ում և կարող եմ հեշտությամբ տրամադրել մնացած 20+ ժամերը համապատասխան գրադարաններ փնտրելու, կազմելու և կապելու համար: Պարզ ասած, ես դուրս եկա: Դա այն է, ինչ մենք որոշեցինք և հանգիստ ավարտեցինք ամեն ինչ Python-ում:

Հիմա, հարկադիր ինքնամեկուսացման ժամանակ, ես որոշեցի պարզել, թե ինչպես գրել ծառայություններ C++-ով: Առաջին բանը, որ պետք է անել, համապատասխան գրադարանի որոշումն էր: Իմ ընտրությունը ընկավ poco, քանի որ այն գրված էր օբյեկտի վրա հիմնված ոճով և պարծենում էր նաև նորմալ փաստաթղթերով։ Նաև հարց առաջացավ հավաքման համակարգի ընտրության վերաբերյալ: Մինչ այս պահը ես աշխատել եմ միայն Visual Studio-ի, IAR-ի և մերկ մեյքֆայլերի հետ: Եվ այս համակարգերից ոչ մեկն ինձ գրավեց, քանի որ ես նախատեսում էի ամբողջ ծառայությունը գործարկել դոկեր կոնտեյներով: Հետո որոշեցի փորձել պարզել cmake-ն ու հետաքրքիր փաթեթի մենեջեր կոնան. Այս փաթեթի կառավարիչը թույլ է տվել գրանցել բոլոր կախվածությունները մեկ ֆայլում

conanfile.txt
[պահանջում է] poco/1.9.3
libpq/11.5

[գեներատորներ] cmake

և պարզ հրամանով «conan install »: տեղադրել անհրաժեշտ գրադարանները: Բնականաբար, անհրաժեշտ էր նաև փոփոխություններ կատարել

CMakeLists.txt

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

Դրանից հետո ես սկսեցի գրադարան փնտրել PostgreSQL-ի հետ աշխատելու համար, քանի որ դա այն գրադարանն էր, որի հետ աշխատելու քիչ փորձ ունեի, և դա այն գրադարանն էր, որի հետ համագործակցում էին մեր Python ծառայությունները: Իսկ դուք գիտե՞ք, թե ինչ եմ սովորել։ Այն գտնվում է POCO-ում: Բայց Conan-ը չգիտի, որ այն գտնվում է POCO-ում և չգիտի, թե ինչպես կառուցել այն, պահեստում կա հնացած կազմաձևման ֆայլ (ես արդեն գրել եմ այս սխալի մասին POCO-ի ստեղծողներին): Սա նշանակում է, որ դուք պետք է փնտրեք այլ գրադարան:

Եվ հետո իմ ընտրությունը ընկավ ոչ այնքան հայտնի գրադարանի վրա libpg. Եվ ես աներևակայելի բախտավոր էի, այն արդեն Կոնանում էր և նույնիսկ հավաքվում և հավաքվում էր:

Հաջորդ քայլը ծառայության ձևանմուշ գրելն էր, որը կարող է մշակել հարցումները:
Մենք պետք է ժառանգենք մեր TemplateServerApp դասը Poco::Util::ServerApplication-ից և անտեսենք հիմնական մեթոդը:

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;
}

Հիմնական մեթոդում մենք պետք է սահմանենք պարամետրերը՝ պորտ, թելերի քանակը և հերթի չափը։ Եվ ամենակարևորը, դուք պետք է նշեք մուտքային հարցումների մշակող: Դա արվում է գործարան ստեղծելով

TemplateRequestHandlerFactory

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

Իմ դեպքում, այն պարզապես ամեն անգամ ստեղծում է նույն մշակիչը՝ TemplateServerAppHandler: Այստեղ մենք կարող ենք տեղադրել մեր բիզնես տրամաբանությունը:

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();
    }
};

Ես նաև ստեղծել եմ դասի ձևանմուշ՝ PostgreSQL-ի հետ աշխատելու համար: Պարզ SQL-ի կատարման համար, օրինակ՝ աղյուսակ ստեղծելու համար, կա մեթոդ ExecuteSQL (). Ավելի բարդ հարցումների կամ տվյալների որոնման համար դուք պետք է կապ ձեռք բերեք միջոցով GetConnection () և օգտագործեք libpg API-ն: (Երևի հետո ես ուղղեմ այս անարդարությունը)։

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;
};

Տվյալների բազայի հետ միանալու բոլոր պարամետրերը վերցված են միջավայրից, այնպես որ դուք նույնպես պետք է ստեղծեք և կարգավորեք .env ֆայլը:

.env

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

Դուք կարող եք տեսնել ամբողջ ծածկագիրը այստեղ github.

Միկրոծառայություններ C++-ում։ Գեղարվեստական, թե իրականություն.

Եվ հիմա գալիս է dockerfile-ը և docker-compose.yml-ը գրելու վերջին փուլը: Անկեղծ ասած, դա խլեց ժամանակի մեծ մասը, և ոչ միայն այն պատճառով, որ ես նոբիկ եմ, որովհետև անհրաժեշտ էր ամեն անգամ վերակառուցել գրադարանները, այլ Կոնանի որոգայթների պատճառով: Օրինակ, որպեսզի conan-ը ներբեռնի, տեղադրի և կառուցի անհրաժեշտ կախվածությունները, բավական չէ, որ նա ներբեռնի «conan install .»-ը, այն նաև պետք է անցնի -s compiler.libcxx=libstdc++11 պարամետրը, այլապես։ Դուք վտանգում եք ստանալ մի շարք սխալներ ձեր դիմումի կապակցման փուլում: Ես խրված եմ այս սխալի հետ մի քանի ժամով, և հուսով եմ, որ այս հոդվածը կօգնի այլ մարդկանց լուծել այս խնդիրը ավելի քիչ ժամանակում:

Հաջորդը, docker-compose.yml-ը գրելուց հետո, ընկերոջս խորհրդով, ավելացրի աջակցություն թխվածքաբլիթի Կտրիչ և այժմ դուք կարող եք ստանալ լիարժեք ձևանմուշ REST API ծառայության համար C++-ում, հարմարեցված միջավայրով և տեղադրված PostgreSQL-ը՝ պարզապես մուտքագրելով «cookiecutter» վահանակի մեջ: https://github.com/KovalevVasiliy/cpp_rest_api_template.git« Եվ հետո «docker-compose up —build».

Հուսով եմ, որ այս ձևանմուշը կօգնի սկսնակներին REST API հավելվածների զարգացման դժվարին ճանապարհին մեծ և հզոր, բայց այնպիսի անշնորհք լեզվով, ինչպիսին C++-ն է:
Բացի այդ, ես բարձր խորհուրդ եմ տալիս կարդալ այստեղ սա է հոդված. Այն ավելի մանրամասն բացատրում է, թե ինչպես աշխատել POCO-ի հետ և գրել ձեր սեփական REST API ծառայությունը:

Source: www.habr.com

Добавить комментарий