# 第 48 章后台工作进程

PostgreSQL 可以扩展为在单独的进程中运行用户提供的代码。此类进程由以下人员启动、停止和监控postgres,这允许它们的生命周期与服务器的状态密切相关。这些进程可以选择附加到 PostgreSQL 的共享内存区域并在内部连接到数据库;它们还可以串行运行多个事务,就像常规的客户端连接的服务器进程一样。此外,通过链接到 libpq,它们可以连接到服务器并像常规客户端应用程序一样运行。

# 警告

使用后台工作进程存在相当大的健壮性和安全风险,因为编写在C语言,他们可以不受限制地访问数据。希望启用包含后台工作进程的模块的管理员应格外小心。只有经过仔细审核的模块才能被允许运行后台工作进程。

后台工作人员可以在 PostgreSQL 启动时通过在中包含模块名称来初始化shared_preload_libraries.希望运行后台工作者的模块可以通过调用来注册它注册后台工作者(后台工作者**工人*)从其_PG_init()功能。后台工作人员也可以在系统启动并运行后通过调用启动RegisterDynamicBackgroundWorker(后台工作者**工人*,背景工作者句柄***处理*).不像注册BackgroundWorker,只能从 postmaster 进程中调用,注册DynamicBackgroundWorker必须从常规后端或其他后台工作人员调用。

结构后台工作者是这样定义的:

typedef void (*bgworker_main_type)(Datum main_arg);
typedef struct BackgroundWorker
{
    char        bgw_name[BGW_MAXLEN];
    char        bgw_type[BGW_MAXLEN];
    int         bgw_flags;
    BgWorkerStartTime bgw_start_time;
    int         bgw_restart_time;       /* in seconds, or BGW_NEVER_RESTART */
    char        bgw_library_name[BGW_MAXLEN];
    char        bgw_function_name[BGW_MAXLEN];
    Datum       bgw_main_arg;
    char        bgw_extra[BGW_EXTRALEN];
    int         bgw_notify_pid;
} BackgroundWorker;

bgw_namebgw_type是在日志消息、进程列表和类似上下文中使用的字符串。bgw_type对于相同类型的所有后台工作人员应该是相同的,以便可以将这些工作人员分组到一个进程列表中,例如。bgw_name另一方面,可以包含有关特定过程的附加信息。(通常,字符串为bgw_name将以某种方式包含类型,但这不是严格要求的。)

bgw_flags是一个位或位掩码,指示模块想要的功能。可能的值为:

BGWORKER_SHMEM_ACCESS

请求共享内存访问。没有共享内存访问权限的工作人员无法访问任何 PostgreSQL 的共享数据结构,例如重量级或轻量级锁、共享缓冲区或工作人员本身可能希望创建和使用的任何自定义数据结构。

BGWORKER_BACKEND_DATABASE_CONNECTION

请求建立数据库连接的能力,以后可以通过该连接运行事务和查询。后台工作人员使用BGWORKER_BACKEND_DATABASE_CONNECTION连接到数据库还必须使用附加共享内存BGWORKER_SHMEM_ACCESS,否则worker启动将失败。

bgw_start_time是服务器状态,在此期间postgres应该开始这个过程;它可以是其中之一BgWorkerStart_PostmasterStart(尽快开始postgres本身已经完成了自己的初始化;请求这个的进程不符合数据库连接的条件),BgWorkerStart_ConsistentState(在热备用中达到一致状态后立即启动,允许进程连接到数据库并运行只读查询),以及BgWorkerStart_RecoveryFinished(系统进入正常读写状态后立即启动)。请注意,最后两个值在非热备用服务器中是等效的。请注意,此设置仅指示何时启动进程;当达到不同的状态时,它们不会停止。

bgw_restart_time是间隔,以秒为单位,postgres如果它崩溃,应该在重新启动进程之前等待。它可以是任何正值,或者BGW_NEVER_RESTART, 表示在崩溃的情况下不重新启动进程。

bgw_library_name是应在其中寻找后台工作人员的初始入口点的库的名称。命名库将由工作进程动态加载,并且bgw_function_name将用于标识要调用的函数。如果从核心代码加载函数,则必须将其设置为“postgres”。

bgw_function_name是动态加载的库中的函数名称,应用作新后台工作程序的初始入口点。

bgw_main_arg是个基准后台工作主函数的参数。这个主函数应该接受一个类型的参数基准并返回空白.bgw_main_arg将作为参数传递。此外,全局变量MyBgworkerEntry指向副本后台工作者注册时通过的结构;工人可能会发现检查这种结构很有帮助。

在 Windows 上(以及其他任何地方EXEC_BACKEND已定义)或在动态后台工作人员中,通过基准通过参考,仅按价值。如果需要参数,最安全的做法是传递一个 int32 或其他小值并将其用作共享内存中分配的数组的索引。如果像一个值字符串或者文本传递,则指针在新的后台工作进程中将无效。

bgw_extra可以包含要传递给后台工作人员的额外数据。不像bgw_main_arg,这个数据不会作为参数传递给worker的main函数,但是可以通过MyBgworkerEntry,如上所述。

bgw_notify_pid是 postmaster 应该发送到的 PostgreSQL 后端进程的 PIDSIGUSR1当进程启动或退出时。对于在 postmaster 启动时注册的 worker,或者当注册 worker 的后端不希望等待 worker 启动时,它应该为 0.否则,它应该被初始化为MyProcPid.

运行后,该进程可以通过调用连接到数据库BackgroundWorkerInitializeConnection(*字符数据库名`,`字符用户名*, *uint32 标志*)要么BackgroundWorkerInitializeConnectionByOid(*椭圆形*, *类用户类*, *uint32 标志*).这允许进程使用SPI界面。如果数据库名称为 NULL 或双胞胎无效,会话没有连接到任何特定的数据库,但可以访问共享目录。如果用户名为 NULL 或用户类无效, 该进程将作为创建的超级用户运行初始化数据库.如果BGWORKER_BYPASS_ALLOWCONN被指定为旗帜可以绕过限制连接到不允许用户连接的数据库。后台工作人员只能调用这两个函数之一,并且只能调用一次。无法切换数据库。

当控制到达后台worker的main函数时,信号最初被阻塞,并且必须被它解除阻塞;这是为了允许进程在必要时自定义其信号处理程序。信号可以通过调用在新进程中解除阻塞BackgroundWorkerUnblockSignals并通过调用阻止背景工作者块信号.

如果bgw_restart_time后台工作人员配置为BGW_NEVER_RESTART,或者如果它以退出代码 0 退出或被终止TerminateBackgroundWorker,它会在退出时被邮局管理员自动注销。否则,它将在通过配置的时间段后重新启动bgw_restart_time,或者如果 postmaster 由于后端故障重新初始化集群,则立即。只需要暂时暂停执行的后端应该使用可中断的睡眠而不是退出;这可以通过调用来实现等待闩锁().确保WL_POSTMASTER_DEATH调用该函数时设置标志,并验证在紧急情况下提示退出的返回码postgres本身已经终止。

当后台工作人员使用注册DynamicBackgroundWorker功能,执行注册的后端可以获取有关工人状态的信息。希望这样做的后端应该传递一个地址背景工作者句柄 *作为第二个论点注册DynamicBackgroundWorker.如果工人注册成功,这个指针将被初始化一个不透明的句柄,随后可以传递给GetBackgroundWorkerPid(*背景工作者句柄*`,`pid_t**)或者终止BackgroundWorker(*背景工作者句柄*`*).获取BackgroundWorkerPid可用于轮询worker的状态:返回值为BGWH_NOT_YET_STARTED表示邮递员还没有启动worker;BGWH_STOPPED表示已经启动但不再运行;和BGWH_STARTED表示当前正在运行。在最后一种情况下,PID 也将通过第二个参数返回。TerminateBackgroundWorker导致邮局局长发送如果它正在运行,则向工作人员发送 SIGTERM`,并在它不运行时立即取消注册。

在某些情况下,注册后台工作者的进程可能希望等待工作者启动。这可以通过初始化来完成bgw_notify_pidMyProcPid然后通过背景工作者句柄 *在注册时获得WaitForBackgroundWorkerStartup(*背景工作者句柄句柄`,`pid_t*)功能。此函数将一直阻塞,直到 postmaster 尝试启动后台工作程序,或者直到 postmaster 死亡。如果后台工作人员正在运行,则返回值为BGWH_STARTED, 并且 PID 将被写入提供的地址。否则,返回值将是BGWH_STOPPED要么BGWH_POSTMASTER_DIED.

进程也可以通过使用WaitForBackgroundWorkerShutdown(*背景工作者句柄句柄`)函数并传递背景工作者句柄 *注册时获得。此函数将阻塞,直到后台工作人员退出或 postmaster 死亡。后台worker退出时,返回值为BGWH_STOPPED, 如果 postmaster 死了,它会返回BGWH_POSTMASTER_DIED`。

后台工作人员可以发送异步通知消息,或者通过使用通知通过 SPI 命令,或直接通过Async_Notify().此类通知将在事务提交时发送。后台工作人员不应注册以接收异步通知命令,因为没有基础设施可供工作人员使用此类通知。

src/test/modules/worker_spi模块包含一个工作示例,它演示了一些有用的技术。

注册后台工作人员的最大数量受限于最大限度_工人_流程.