C++ da mikroservislar. Fantastikami yoki haqiqatmi?

C++ da mikroservislar. Fantastikami yoki haqiqatmi?

Ushbu maqolada men shablonni (cookiecutter) qanday yaratganim va docker/docker-compose va conan paket menejeri yordamida C++ da REST API xizmatini yozish uchun muhitni o'rnatganim haqida gapiraman.

Men backend dasturchisi sifatida ishtirok etgan navbatdagi hackathon davomida keyingi mikroservisni yozish uchun nimadan foydalanish kerakligi haqida savol tug'ildi. Hozirgacha yozilganlarning hammasini men va men yozganman o'rtoq Pythonda, chunki mening hamkasbim bu sohada mutaxassis va professional ravishda ishlab chiqilgan backends, men esa odatda o'rnatilgan tizimlar ishlab chiqaruvchisi bo'lganman va ajoyib va ​​dahshatli C++ da yozganman va men Pythonni universitetda o'rganganman.

Shunday qilib, biz yuqori yuklangan xizmatni yozish vazifasiga duch keldik, uning asosiy vazifasi unga keladigan ma'lumotlarni oldindan qayta ishlash va ma'lumotlar bazasiga yozish edi. Va yana bir tutun tanaffusdan so'ng, bir do'stim menga C++ dasturchisi sifatida ushbu xizmatni professionallardan foydalangan holda yozishni taklif qildi. Buning ta'kidlashicha, u tezroq, samaraliroq bo'ladi va umuman olganda, hakamlar hay'ati jamoaning resurslarini qanday boshqarishni bilishimizdan xursand bo'ladi. Men hech qachon C++ da bunday ishlarni qilmaganman va qolgan 20+ soatni mos kutubxonalarni qidirish, kompilyatsiya qilish va ulashga bemalol bag'ishlashim mumkinligini aytdim. Oddiy qilib aytganda, men o'zimni to'g'rilab qo'ydim. Biz shunday qaror qildik va Python-da hamma narsani xotirjam yakunladik.

Endi, majburiy o'zini-o'zi izolyatsiya qilish paytida men C++ da xizmatlarni qanday yozishni aniqlashga qaror qildim. Birinchi narsa, tegishli kutubxonani tanlash edi. Mening tanlovim to'g'ri keldi POCO, chunki u ob'ektga yo'naltirilgan uslubda yozilgan va oddiy hujjatlar bilan maqtangan. Shuningdek, montaj tizimini tanlash haqida savol tug'ildi. Shu paytgacha men faqat Visual Studio, IAR va yalang'och makefillar bilan ishladim. Va bu tizimlarning hech biri menga yoqmadi, chunki men butun xizmatni docker konteynerida ishlatishni rejalashtirgan edim. Keyin men cmake va qiziqarli paket menejerini aniqlashga qaror qildim konan. Ushbu paket menejeri sizga barcha bog'liqliklarni bitta faylda ro'yxatdan o'tkazish imkonini berdi

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

[generatorlar] cmake

va oddiy buyruq bilan "conan install ." kerakli kutubxonalarni o'rnating. Tabiiyki, bunga ham o'zgartirishlar kiritish kerak edi

CMakeLists.txt

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

Shundan so'ng, men PostgreSQL bilan ishlash uchun kutubxona izlay boshladim, chunki u bilan ishlash tajribam kam edi va bu bizning Python xizmatlarimiz bilan o'zaro aloqada bo'lgan kutubxona edi. Va men nimani o'rganganimni bilasizmi? U POCO ichida! Ammo Konan uning POCO-da ekanligini bilmaydi va uni qanday qurishni bilmaydi, omborda eskirgan konfiguratsiya fayli mavjud (men bu xato haqida POCO yaratuvchilariga allaqachon yozganman). Bu siz boshqa kutubxona qidirishingiz kerakligini anglatadi.

Va keyin mening tanlovim kamroq mashhur kutubxonaga tushdi libpg. Va men juda omadli edim, u allaqachon konanda bo'lgan va hatto yig'ilib, yig'ilayotgan edi.

Keyingi qadam so'rovlarni qayta ishlay oladigan xizmat shablonini yozish edi.
Biz TemplateServerApp sinfimizni Poco::Util::ServerApplication-dan meros qilib olishimiz va asosiy usulni bekor qilishimiz kerak.

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

Asosiy usulda biz parametrlarni o'rnatishimiz kerak: port, iplar soni va navbat hajmi. Va eng muhimi, siz kiruvchi so'rovlar uchun ishlov beruvchini belgilashingiz kerak. Bu zavod yaratish orqali amalga oshiriladi

TemplateRequestHandlerFactory

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

Mening holimda u har safar bir xil ishlov beruvchini yaratadi - TemplateServerAppHandler. Bu erda biz biznes mantiqimizni joylashtirishimiz mumkin.

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

Men PostgreSQL bilan ishlash uchun sinf shablonini ham yaratdim. Jadval yaratish kabi oddiy SQL-ni bajarish uchun usul mavjud ExecuteSQL(). Murakkab so'rovlar yoki ma'lumotlarni olish uchun siz orqali ulanishingiz kerak bo'ladi GetConnection() va libpg API dan foydalaning. (Balki keyinroq bu adolatsizlikni tuzatarman).

ma'lumotlar bazasi

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

Ma'lumotlar bazasiga ulanish uchun barcha parametrlar muhitdan olingan, shuning uchun siz .env faylini yaratishingiz va sozlashingiz kerak.

.NS

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

Siz barcha kodlarni ko'rishingiz mumkin github.

C++ da mikroservislar. Fantastikami yoki haqiqatmi?

Endi dockerfile va docker-compose.yml faylini yozishning yakuniy bosqichi keladi. Rostini aytsam, bu ko'p vaqtni oldi va nafaqat men noobman, chunki har safar kutubxonalarni qayta qurish kerak edi, balki Konanning tuzoqlari tufayli. Misol uchun, conan kerakli bog'liqliklarni yuklab olishi, o'rnatishi va qurishi uchun "conan install ." ni yuklab olishning o'zi etarli emas, shuningdek, -s compiler.libcxx=libstdc++11 parametrini o'tkazishi kerak, aks holda. ilovangizni ulash bosqichida bir qator xatolarga yo'l qo'yish xavfi bor. Men bu xato bilan bir necha soat davomida qotib qoldim va umid qilamanki, ushbu maqola boshqa odamlarga bu muammoni qisqa vaqt ichida hal qilishga yordam beradi.

Keyin, docker-compose.yml ni yozganimdan so'ng, do'stimning maslahati bilan men qo'llab-quvvatlashni qo'shdim pechenyechi va endi siz konsolga "cookiecutter" ni kiritish orqali o'zingizga moslashtirilgan muhit va PostgreSQL o'rnatilgan C++ tilida REST API xizmati uchun to'liq huquqli shablonni olishingiz mumkin. https://github.com/KovalevVasiliy/cpp_rest_api_template.git" Va keyin "docker-compose up -build".

Umid qilamanki, ushbu shablon yangi boshlanuvchilarga REST API ilovalarini buyuk va kuchli, ammo C++ kabi bema'ni tilda ishlab chiqishning qiyin yo'lida yordam beradi.
Bundan tashqari, men bu erda o'qishni tavsiya qilaman bu maqola. U POCO bilan qanday ishlash va o'z REST API xizmatingizni yozishni batafsilroq tushuntiradi.

Manba: www.habr.com

a Izoh qo'shish