• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

haraka / Haraka / 26107975229

19 May 2026 03:39PM UTC coverage: 71.554% (-0.05%) from 71.6%
26107975229

push

github

web-flow
change: replace forEach with es6 style for...of (#3569)

1719 of 2239 branches covered (76.78%)

33 of 52 new or added lines in 6 files covered. (63.46%)

3 existing lines in 1 file now uncovered.

7682 of 10736 relevant lines covered (71.55%)

21.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

46.7
/plugins/process_title.js
1
// process_title
8✔
2

8✔
3
const outbound = require('../outbound')
8✔
4

8✔
5
function setupInterval(title, server) {
8✔
6
    // Set up a timer to update title
2✔
7
    return setInterval(() => {
2✔
8
        // Connections per second
2✔
9
        const av_cps = Math.round((server.notes.pt_connections / process.uptime()) * 100) / 100
×
10
        const cps = server.notes.pt_connections - server.notes.pt_cps_diff
×
11
        if (cps > server.notes.pt_cps_max) server.notes.pt_cps_max = cps
×
12
        server.notes.pt_cps_diff = server.notes.pt_connections
×
13
        // Recipients per second
×
14
        const av_rps = Math.round((server.notes.pt_recipients / process.uptime()) * 100) / 100
×
15
        const rps = server.notes.pt_recipients - server.notes.pt_rps_diff
×
16
        if (rps > server.notes.pt_rps_max) server.notes.pt_rps_max = rps
×
17
        server.notes.pt_rps_diff = server.notes.pt_recipients
×
18
        // Recipients per message
×
19
        const rpm = Math.round((server.notes.pt_recipients / server.notes.pt_messages) * 100) / 100 || 0
×
20
        // Messages per second
×
21
        const av_mps = Math.round((server.notes.pt_messages / process.uptime()) * 100) / 100
×
22
        const mps = server.notes.pt_messages - server.notes.pt_mps_diff
×
23
        if (mps > server.notes.pt_mps_max) server.notes.pt_mps_max = mps
×
24
        server.notes.pt_mps_diff = server.notes.pt_messages
×
25
        // Messages per connection
×
26
        const mpc = Math.round((server.notes.pt_messages / server.notes.pt_connections) * 100) / 100 || 0
×
27

×
28
        const out = server.notes.pt_out_stats || outbound.get_stats()
×
29
        if (/\(worker\)/.test(title)) {
×
30
            process.send({ event: 'process_title.outbound_stats', data: out })
×
31
        }
×
32
        // Update title
×
33
        let new_title = `${title} cn=${server.notes.pt_connections} cc=${server.notes.pt_concurrent} cps=${cps}/${av_cps}/${server.notes.pt_cps_max} rcpts=${server.notes.pt_recipients}/${rpm} rps=${rps}/${av_rps}/${server.notes.pt_rps_max} msgs=${server.notes.pt_messages}/${mpc} mps=${mps}/${av_mps}/${server.notes.pt_mps_max} out=${out} `
×
34
        if (/\(master\)/.test(title)) {
×
35
            new_title += `respawn=${server.notes.pt_child_exits} `
×
36
        }
×
37
        process.title = new_title
×
38
    }, 1000)
×
39
}
×
40

×
41
exports.hook_init_master = function (next, server) {
8✔
42
    server.notes.pt_connections = 0
1✔
43
    server.notes.pt_concurrent = 0
1✔
44
    server.notes.pt_cps_diff = 0
1✔
45
    server.notes.pt_cps_max = 0
1✔
46
    server.notes.pt_recipients = 0
1✔
47
    server.notes.pt_rps_diff = 0
1✔
48
    server.notes.pt_rps_max = 0
1✔
49
    server.notes.pt_messages = 0
1✔
50
    server.notes.pt_mps_diff = 0
1✔
51
    server.notes.pt_mps_max = 0
1✔
52
    server.notes.pt_child_exits = 0
1✔
53
    let title = 'Haraka'
1✔
54
    if (server.cluster) {
1✔
55
        title = 'Haraka (master)'
1!
56
        process.title = title
×
57
        server.notes.pt_concurrent_cluster = {}
×
58
        server.notes.pt_new_out_stats = [0, 0, 0, 0]
×
59
        const { cluster } = server
×
60
        const recvMsg = (msg) => {
×
61
            let count
×
62
            switch (msg.event) {
×
63
                case 'process_title.connect':
×
64
                    server.notes.pt_connections++
×
65
                    server.notes.pt_concurrent_cluster[msg.wid]++
×
66
                    count = 0
×
NEW
67
                    for (const id of Object.keys(server.notes.pt_concurrent_cluster)) {
×
68
                        count += server.notes.pt_concurrent_cluster[id]
×
NEW
69
                    }
×
70
                    server.notes.pt_concurrent = count
×
71
                    break
×
72
                case 'process_title.disconnect':
×
73
                    server.notes.pt_concurrent_cluster[msg.wid]--
×
74
                    count = 0
×
NEW
75
                    for (const id of Object.keys(server.notes.pt_concurrent_cluster)) {
×
76
                        count += server.notes.pt_concurrent_cluster[id]
×
NEW
77
                    }
×
78
                    server.notes.pt_concurrent = count
×
79
                    break
×
80
                case 'process_title.recipient':
×
81
                    server.notes.pt_recipients++
×
82
                    break
×
83
                case 'process_title.message':
×
84
                    server.notes.pt_messages++
×
85
                    break
×
86
                case 'process_title.outbound_stats': {
×
87
                    const out_stats = msg.data.split('/')
×
88
                    for (let i = 0; i < out_stats.length; i++) {
×
89
                        server.notes.pt_new_out_stats[i] += parseInt(out_stats[i], 10)
×
90
                    }
×
91
                    server.notes.pt_new_out_stats[3]++
×
92
                    // Check if we got all results back yet
×
93
                    if (server.notes.pt_new_out_stats[3] === Object.keys(cluster.workers).length) {
×
94
                        server.notes.pt_out_stats = server.notes.pt_new_out_stats.slice(0, 3).join('/')
×
95
                        server.notes.pt_new_out_stats = [0, 0, 0, 0]
×
96
                    }
×
97
                }
×
98
                // fall through
×
99
                default:
×
100
                // Unknown message
×
101
            }
×
102
        }
×
103
        // Register any new workers
×
104
        cluster.on('fork', (worker) => {
×
105
            server.notes.pt_concurrent_cluster[worker.id] = 0
×
106
            cluster.workers[worker.id].on('message', recvMsg)
×
107
        })
×
108
        cluster.on('exit', (worker) => {
×
109
            delete server.notes.pt_concurrent_cluster[worker.id]
×
110
            // Update concurrency
×
111
            let count = 0
×
NEW
112
            for (const id of Object.keys(server.notes.pt_concurrent_cluster)) {
×
113
                count += server.notes.pt_concurrent_cluster[id]
×
NEW
114
            }
×
115
            server.notes.pt_concurrent = count
×
116
            server.notes.pt_child_exits++
×
117
        })
×
118
    }
×
119
    this._interval = setupInterval(title, server)
1✔
120
    next()
1✔
121
}
1✔
122

1✔
123
exports.hook_init_child = function (next, server) {
8✔
124
    server.notes.pt_connections = 0
1✔
125
    server.notes.pt_concurrent = 0
1✔
126
    server.notes.pt_cps_diff = 0
1✔
127
    server.notes.pt_cps_max = 0
1✔
128
    server.notes.pt_recipients = 0
1✔
129
    server.notes.pt_rps_diff = 0
1✔
130
    server.notes.pt_rps_max = 0
1✔
131
    server.notes.pt_messages = 0
1✔
132
    server.notes.pt_mps_diff = 0
1✔
133
    server.notes.pt_mps_max = 0
1✔
134
    process.title = 'Haraka (worker)'
1✔
135
    this._interval = setupInterval(process.title, server)
1✔
136
    next()
1✔
137
}
1✔
138

1✔
139
exports.shutdown = function () {
8✔
140
    this.logdebug(`Shutting down interval: ${this._interval}`)
1✔
141
    clearInterval(this._interval)
1✔
142
}
1✔
143

1✔
144
exports.hook_connect_init = (next, connection) => {
8✔
145
    const { server } = connection
1✔
146
    connection.notes.pt_connect_run = true
1✔
147
    if (server.cluster) {
1✔
148
        const { worker } = server.cluster
1!
149
        worker.send({ event: 'process_title.connect', wid: worker.id })
×
150
    }
×
151
    server.notes.pt_connections++
1✔
152
    server.notes.pt_concurrent++
1✔
153
    next()
1✔
154
}
1✔
155

1✔
156
exports.hook_disconnect = (next, connection) => {
8✔
157
    const { server } = connection
2✔
158
    // Check that the hook above ran
2✔
159
    // It might not if the disconnection is immediate
2✔
160
    // echo "QUIT" | nc localhost 25
2✔
161
    // will exhibit this behaviour.
2✔
162
    let worker
2✔
163
    if (!connection.notes.pt_connect_run) {
2✔
164
        if (server.cluster) {
2✔
165
            worker = server.cluster.worker
1!
166
            worker.send({ event: 'process_title.connect', wid: worker.id })
×
167
        }
×
168
        server.notes.pt_connections++
1✔
169
        server.notes.pt_concurrent++
1✔
170
    }
1✔
171
    if (server.cluster) {
2✔
172
        worker = server.cluster.worker
2!
173
        worker.send({ event: 'process_title.disconnect', wid: worker.id })
×
174
    }
×
175
    server.notes.pt_concurrent--
2✔
176
    next()
2✔
177
}
2✔
178

2✔
179
exports.hook_rcpt = (next, connection) => {
8✔
180
    const { server } = connection
1✔
181
    if (server.cluster) {
1✔
182
        const { worker } = server.cluster
1!
183
        worker.send({ event: 'process_title.recipient' })
×
184
    }
×
185
    server.notes.pt_recipients++
1✔
186
    next()
1✔
187
}
1✔
188

1✔
189
exports.hook_data = (next, connection) => {
8✔
190
    const { server } = connection
1✔
191
    if (server.cluster) {
1✔
192
        const { worker } = server.cluster
1!
193
        worker.send({ event: 'process_title.message' })
×
194
    }
×
195
    server.notes.pt_messages++
1✔
196
    next()
1✔
197
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc