Микросервис у Ц++. Фикција или стварност?

Микросервис у Ц++. Фикција или стварност?

У овом чланку ћу говорити о томе како сам направио шаблон (цоокиецуттер) и подесио окружење за писање РЕСТ АПИ услуге у Ц++ користећи доцкер/доцкер-цомпосе и цонан менаџер пакета.

Током следећег хакатона, у коме сам учествовао као бацкенд девелопер, поставило се питање шта користити за писање следећег микросервиса. Све што је до сада написано написали смо ја и моји друже у Питхон-у, пошто је мој колега био стручњак у овој области и професионално развијао бекендове, док сам ја генерално био програмер уграђених система и писао у сјајном и страшном Ц++-у, а Пајтон сам научио тек на универзитету.

Дакле, били смо суочени са задатком да напишемо сервис са великим оптерећењем, чији је главни задатак био да претходно обради податке који су му пристизали и упише их у базу података. И после још једне паузе за дим, пријатељ ми је предложио да ја, као Ц++ програмер, напишем ову услугу користећи професионалце. Тврди се да ће то бити брже, продуктивније и генерално, жири ће бити одушевљен како знамо да управљамо ресурсима тима. На шта сам одговорио да никада нисам радио такве ствари у Ц++-у и да бих лако могао да посветим преосталих 20+ сати тражењу, компајлирању и повезивању одговарајућих библиотека. Једноставно речено, одлепио сам. То је оно за шта смо се одлучили и мирно завршили све у Питхон-у.

Сада, током принудне самоизолације, одлучио сам да смислим како да напишем сервисе у Ц++. Прво је требало да се одлучи за одговарајућу библиотеку. Мој избор је пао ПОЦО, пошто је написан у објектно оријентисаном стилу и такође се може похвалити нормалном документацијом. Такође, поставило се питање избора система монтаже. До ове тачке сам радио само са Висуал Студио-ом, ИАР-ом и голим маке-фајловима. И ниједан од ових система ми се није допао, пошто сам планирао да покренем целу услугу у доцкер контејнеру. Онда сам одлучио да покушам да пронађем цмаке и занимљив менаџер пакета цонан. Овај менаџер пакета вам је омогућио да региструјете све зависности у једној датотеци

цонанфиле.ткт
[захтева]поцо/1.9.3
либпк/11.5

[генератори] цмаке

и једноставном командом "цонан инсталл ." инсталирати потребне библиотеке. Наравно, било је потребно и измене у

ЦМакеЛистс.ткт

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

Након тога, почео сам да тражим библиотеку за рад са ПостгреСКЛ-ом, пошто је то била она са којом сам имао мало искуства у раду, а такође је била и она са којом су наши Питхон сервиси комуницирали. И знате ли шта сам научио? У ПОЦО је! Али Цонан не зна да је у ПОЦО-у и не зна како да га направи; у спремишту постоји застарела конфигурациона датотека (већ сам писао о овој грешци креаторима ПОЦО-а). То значи да ћете морати да потражите другу библиотеку.

А онда је мој избор пао на мање популарну библиотеку либпг. И имао сам невероватну срећу, већ је био у Конану и чак се склапао и склапао.

Следећи корак је био писање шаблона услуге који може да обрађује захтеве.
Морамо наследити нашу ТемплатеСерверАпп класу од Поцо::Утил::СерверАпплицатион и заменити главни метод.

ТемплатеСерверАпп

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

У главном методу морамо подесити параметре: порт, број нити и величину реда. И што је најважније, морате навести руковаоца за долазне захтеве. Ово се ради стварањем фабрике

ТемплатеРекуестХандлерФацтори

class TemplateRequestHandlerFactory : public HTTPRequestHandlerFactory
{
public:
    virtual HTTPRequestHandler* createRequestHandler(const HTTPServerRequest & request)
    {
        return new 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();
    }
};

Такође сам направио шаблон класе за рад са ПостгреСКЛ-ом. За извођење једноставног СКЛ-а, као што је креирање табеле, постоји метод ЕкецутеСКЛ(). За сложеније упите или преузимање података, мораћете да успоставите везу преко ГетЦоннецтион() и користите либпг АПИ. (Можда ћу касније исправити ову неправду).

База података

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

Сви параметри за повезивање са базом података преузети су из окружења, тако да је потребно да креирате и конфигуришете .енв датотеку

.енв

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

Можете видети сав код на гитхуб.

Микросервис у Ц++. Фикција или стварност?

И сада долази последња фаза писања доцкерфиле-а и доцкер-цомпосе.имл. Да будем искрен, ово је одузело већину времена, и то не само зато што сам нооб, јер је сваки пут било потребно обнављати библиотеке, већ и због замки Конана. На пример, да би цонан преузео, инсталирао и изградио потребне зависности, није довољно да преузме „цонан инсталл .“, већ треба и да проследи параметар -с цомпилер.либцкк=либстдц++11, у супротном ризикујете да добијете гомилу грешака у фази повезивања ваше апликације. Заглавио сам са овом грешком неколико сати и надам се да ће овај чланак помоћи другим људима да реше овај проблем за краће време.

Затим, након што сам написао доцкер-цомпосе.имл, по савету мог пријатеља, додао сам подршку колачић и сада можете себи набавити пуноправни шаблон за РЕСТ АПИ услугу у Ц++, са прилагођеним окружењем и инсталираним ПостгреСКЛ-ом, једноставним уношењем „цоокиецуттер“-а у конзолу https://github.com/KovalevVasiliy/cpp_rest_api_template.git" А онда „доцкер-цомпосе уп —буилд“.

Надам се да ће овај шаблон помоћи почетницима на њиховом тешком путу развоја РЕСТ АПИ апликација на сјајном и моћном, али тако незграпном језику као што је Ц++.
Такође, топло препоручујем читање овде ово чланак. Објашњава детаљније како да радите са ПОЦО и напишете сопствену РЕСТ АПИ услугу.

Извор: ввв.хабр.цом

Додај коментар