Microwasanaethau yn C++. Ffuglen neu realiti?

Microwasanaethau yn C++. Ffuglen neu realiti?

Yn yr erthygl hon byddaf yn siarad am sut y creais dempled (cookiecutter) a sefydlu amgylchedd ar gyfer ysgrifennu gwasanaeth API REST yn C ++ gan ddefnyddio docker/docker-compose a'r rheolwr pecyn conan.

Yn ystod yr hacathon nesaf, y cymerais ran ynddo fel datblygwr backend, cododd y cwestiwn beth i'w ddefnyddio i ysgrifennu'r microwasanaeth nesaf. Mae popeth sydd wedi'i ysgrifennu hyd yn hyn wedi'i ysgrifennu gennyf fi a fy cymrawd yn Python, gan fod fy nghydweithiwr yn arbenigwr yn y maes hwn ac wedi datblygu backends yn broffesiynol, tra roeddwn yn gyffredinol yn ddatblygwr systemau wedi'i fewnosod ac yn ysgrifennu yn y C++ gwych ac ofnadwy, a dysgais Python yn y brifysgol.

Felly, roeddem yn wynebu'r dasg o ysgrifennu gwasanaeth llwyth uchel, a'r prif dasg oedd rhag-brosesu'r data a oedd yn dod ato a'i ysgrifennu i'r gronfa ddata. Ac ar ôl seibiant mwg arall, awgrymodd ffrind fy mod i, fel datblygwr C ++, yn ysgrifennu'r gwasanaeth hwn gan ddefnyddio'r manteision. Gan ddadlau y bydd hyn yn gyflymach, yn fwy cynhyrchiol, ac yn gyffredinol, bydd y rheithgor wrth eu bodd â sut rydym yn gwybod sut i reoli adnoddau'r tîm. Atebais nad oeddwn erioed wedi gwneud pethau o'r fath yn C++ ac y gallwn yn hawdd neilltuo'r 20+ awr sy'n weddill i chwilio, llunio a chysylltu llyfrgelloedd addas. Yn syml, yr wyf yn cyweirio allan. Dyna beth wnaethon ni benderfynu arno a chwblhau popeth yn bwyllog yn Python.

Nawr, yn ystod yr hunan-ynysu gorfodol, penderfynais ddarganfod sut i ysgrifennu gwasanaethau yn C ++. Y peth cyntaf i'w wneud oedd penderfynu ar lyfrgell addas. Syrthiodd fy newis ymlaen Poco, gan ei fod wedi'i ysgrifennu mewn arddull gwrthrych-gyfeiriadol a hefyd yn cynnwys dogfennaeth arferol. Hefyd, cododd y cwestiwn am ddewis system ymgynnull. Hyd at y pwynt hwn dim ond gyda Visual Studio, IAR a moel makefiles rydw i wedi gweithio. Ac nid oedd yr un o'r systemau hyn yn apelio ataf, gan fy mod yn bwriadu rhedeg y gwasanaeth cyfan mewn cynhwysydd docwr. Yna penderfynais geisio darganfod cmake a rheolwr pecyn diddorol Conan. Roedd y rheolwr pecyn hwn yn caniatáu ichi gofrestru pob dibyniaeth mewn un ffeil

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

[generaduron] cmake

a gyda gorchymyn syml " conan install ." gosod y llyfrgelloedd angenrheidiol. Yn naturiol, roedd hefyd angen gwneud newidiadau i

CMakeLists.txt

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

Ar ôl hynny, dechreuais chwilio am lyfrgell i weithio gyda PostgreSQL, gan mai dyma'r un nad oedd gen i fawr o brofiad o weithio ag ef, a dyma hefyd oedd yr un yr oedd ein gwasanaethau Python yn rhyngweithio ag ef. Ac ydych chi'n gwybod beth ddysgais i? Mae yn POCO! Ond nid yw Conan yn gwybod ei fod yn POCO ac nid yw'n gwybod sut i'w adeiladu; mae ffeil ffurfweddu hen ffasiwn yn yr ystorfa (rwyf eisoes wedi ysgrifennu am y gwall hwn at grewyr POCO). Mae hyn yn golygu y bydd yn rhaid i chi chwilio am lyfrgell arall.

Ac yna disgynnodd fy newis ar lyfrgell lai poblogaidd libpg. Ac roeddwn i'n anhygoel o lwcus, roedd eisoes mewn conan ac roedd hyd yn oed yn cael ei ymgynnull a'i ymgynnull.

Y cam nesaf oedd ysgrifennu templed gwasanaeth a all brosesu ceisiadau.
Rhaid inni etifeddu ein dosbarth TemplateServerApp gan Poco ::Util ::ServerApplication a diystyru'r prif ddull.

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

Yn y prif ddull rhaid inni osod y paramedrau: porthladd, nifer yr edafedd a maint y ciw. Ac yn bwysicaf oll, rhaid i chi nodi triniwr ar gyfer ceisiadau sy'n dod i mewn. Gwneir hyn trwy greu ffatri

TemplateRequestHandlerFactory

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

Yn fy achos i, yn syml, mae'n creu'r un triniwr bob tro - TemplateServerAppHandler. Dyma lle gallwn osod ein rhesymeg busnes.

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

Creais hefyd dempled dosbarth i weithio gyda PostgreSQL. I berfformio SQL syml, fel creu tabl, mae yna ddull GweithreduSQL(). Ar gyfer ymholiadau mwy cymhleth neu adalw data, bydd yn rhaid i chi gael cysylltiad trwy GetConnection() a defnyddio'r API libpg. (Efallai yn ddiweddarach y byddaf yn cywiro'r anghyfiawnder hwn).

Cronfa Ddata

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

Cymerir yr holl baramedrau ar gyfer cysylltu â'r gronfa ddata o'r amgylchedd, felly mae angen i chi hefyd greu a ffurfweddu'r ffeil .env

.env

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

Gallwch weld y cod i gyd yn github.

Microwasanaethau yn C++. Ffuglen neu realiti?

Ac yn awr daw'r cam olaf o ysgrifennu'r dockerfile a docker-compose.yml. A dweud y gwir, cymerodd hyn y rhan fwyaf o'r amser, ac nid yn unig oherwydd fy mod yn noob, oherwydd bod angen ailadeiladu'r llyfrgelloedd bob tro, ond oherwydd peryglon conan. Er enghraifft, er mwyn i conan lawrlwytho, gosod ac adeiladu'r dibyniaethau angenrheidiol, nid yw'n ddigon iddo lawrlwytho "conan install .", mae angen iddo hefyd basio'r paramedr -s compiler.libcxx=libstdc++11, fel arall rydych mewn perygl o gael llawer o wallau ar y cam cysylltu eich cais. Rwyf wedi bod yn sownd â'r gwall hwn ers sawl awr a gobeithio y bydd yr erthygl hon yn helpu pobl eraill i ddatrys y broblem hon mewn llai o amser.

Nesaf, ar ôl ysgrifennu docker-compose.yml, ar gyngor fy ffrind, ychwanegais gefnogaeth cookiecutter a nawr gallwch chi gael templed cyflawn i chi'ch hun ar gyfer gwasanaeth API REST yn C ++, gydag amgylchedd wedi'i addasu, a PostgreSQL wedi'i osod, dim ond trwy nodi “cookiecutter” yn y consol https://github.com/KovalevVasiliy/cpp_rest_api_template.git" Ac yna “docer-compose up —build”.

Rwy'n gobeithio y bydd y templed hwn yn helpu dechreuwyr ar eu llwybr anodd o ddatblygu cymwysiadau REST API yn y gwych a'r pwerus, ond iaith mor drwsgl fel C ++.
Hefyd, rwy'n argymell darllen yma yn fawr hyn erthygl. Mae'n esbonio'n fanylach sut i weithio gyda POCO ac ysgrifennu eich gwasanaeth REST API eich hun.

Ffynhonnell: hab.com

Ychwanegu sylw