Layanan microser di C ++. Fiksi atau kenyataan?



Pada artikel ini saya akan berbicara tentang bagaimana saya membuat juru masak dan mengatur lingkungan untuk menulis layanan REST API di C ++ menggunakan docker / docker-compose dan pengelola paket conan.


Selama hackathon berikutnya, di mana saya berpartisipasi sebagai pengembang backend, muncul pertanyaan tentang apa yang harus ditulis pada microservice berikutnya. Segala sesuatu yang ditulis pada saat ini ditulis oleh saya dan teman saya di Python, karena kolega saya adalah seorang ahli dalam bidang ini dan secara profesional terlibat dalam pengembangan backend, sementara saya umumnya adalah pengembang untuk sistem embedded dan menulis dalam C yang hebat dan mengerikan. ++, dan Python baru belajar di universitas.


Jadi, kami menghadapi tugas untuk menulis layanan yang sangat dimuat, tugas utama di antaranya adalah preprocessing dari data yang datang kepadanya dan menulisnya ke database. Dan setelah berhenti merokok lagi, seorang teman menyarankan agar saya, sebagai pengembang C ++, menulis layanan ini pada plus. Berdebat dengan mengatakan bahwa ini akan lebih cepat, lebih produktif, dan memang, juri akan senang dengan bagaimana kita dapat mengelola sumber daya tim. Saya menjawab bahwa saya belum pernah melakukan hal-hal seperti itu di C ++ dan saya dapat dengan mudah mencurahkan sisa 20+ jam untuk menemukan, menyusun, dan menghubungkan perpustakaan yang sesuai. Sederhananya, saya takut. Itulah yang mereka putuskan dan dengan tenang menambahkan segalanya ke Python.


, , ++. , , . POCO, - , . , . Visual Studio, IAR «» makefile. , docker-. cmake conan.

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

[generators]
cmake

dan dengan perintah sederhana "conan install." instal perpustakaan yang diperlukan. Secara alami, perubahan juga diperlukan dalam

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

Setelah itu, saya mulai mencari perpustakaan untuk bekerja dengan PostgreSQL, karena dengan itu saya memiliki sedikit pengalaman, dan dengan itu layanan Python kami berinteraksi. Dan Anda tahu apa yang saya temukan? Dia ada di POCO! Tetapi conan tidak tahu bahwa itu ada di POCO dan tidak tahu bagaimana membangunnya, file konfigurasi yang sudah usang ada di repositori (saya sudah menulis tentang kesalahan ini kepada pembuat POCO). Jadi, Anda harus mencari perpustakaan lain.

Dan kemudian pilihan saya jatuh pada perpustakaan libpg yang kurang populer . Dan saya sangat beruntung, dia sudah berada di conan dan bahkan berkumpul dan berkumpul.

Langkah selanjutnya adalah menulis templat layanan yang dapat menangani permintaan.
Kita harus mewarisi kelas TemplateServerApp kami dari Poco :: Util :: ServerApplication dan mengganti metode utama.

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


Dalam metode utama, kita harus mengatur parameter: port, jumlah utas dan ukuran antrian. Dan yang paling penting, Anda harus menentukan penangan permintaan yang masuk. Ini dilakukan melalui penciptaan pabrik.

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


Dalam kasus saya, itu hanya membuat penangan yang sama setiap kali - TemplateServerAppHandler. Di sinilah kita dapat memposisikan logika bisnis kita.

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

Saya juga membuat templat kelas untuk bekerja dengan PostgreSQL. Untuk menjalankan SQL sederhana, misalnya untuk membuat tabel, ada metode ExecuteSQL () . Untuk kueri atau pengambilan data yang lebih kompleks, Anda harus mendapatkan koneksi melalui GetConnection () dan menggunakan API libpg. (Mungkin saya akan memperbaiki ketidakadilan ini).

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

Semua parameter untuk terhubung ke database diambil dari lingkungan, jadi Anda juga perlu membuat dan mengonfigurasi file .env

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


Anda dapat melihat semua kode di github.



dockerfile docker-compose.yml. , , , , , - conan. , , conan , , «conan install .», -s compiler.libcxx=libstdc++11, . , , .


, docker-compose.yml, cookiecutter REST API ++, c , PostgreSQL, «cookiecutter https://github.com/KovalevVasiliy/cpp_rest_api_template.git». «docker-compose up --build».


, REST API , , ++.
, . POCO REST API .


All Articles