File: index.cpp

package info (click to toggle)
bibledit-cloud 5.1.036-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 250,636 kB
  • sloc: xml: 915,934; ansic: 261,349; cpp: 92,628; javascript: 32,542; sh: 4,915; makefile: 586; php: 69
file content (284 lines) | stat: -rw-r--r-- 10,222 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/*
Copyright (©) 2003-2025 Teus Benschop.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/


#include <timer/index.h>
#include <database/logs.h>
#include <database/config/general.h>
#include <database/state.h>
#include <config/globals.h>
#include <filter/string.h>
#include <filter/date.h>
#include <tasks/logic.h>
#include <tasks/run.h>
#include <sendreceive/logic.h>
#include <client/logic.h>
#include <changes/logic.h>
#include <checks/logic.h>
#include <export/logic.h>
#include <developer/logic.h>
#include <setup/logic.h>
#include <journal/logic.h>


// CPU-intensive actions run at night.
// This keeps the site more responsive during the day.


// The order in which the following nightly scripts run is important.
// Any of those scripts may influence the subsequent ones.
// The order is such that all information generated is as recent as possible.
// More important tasks are done first, and the less important ones at the end.
// This leads to an order as visible in the code below.


void timer_index ()
{
  int previous_second { -1 };
  int previous_minute { -1 };
  int previous_fraction { -1 };
  [[maybe_unused]] int google_translate_authentication_token_age_minute { 0 };
  
#ifdef HAVE_CLOUD
  // Right after startup, update the Google Translate access token.
  tasks_logic_queue(task::get_google_access_token);
#endif
  
  while (config_globals_webserver_running) {

    try {

      // Wait shortly.
      std::this_thread::sleep_for (std::chrono::milliseconds (100));
      
      // Wait till the data structures have been initialized.
      setup_wait_till_main_folders_present ();
      if (!config_globals_data_initialized) continue;
      
      // The current time, localized.
      int local_seconds = filter::date::local_seconds (filter::date::seconds_since_epoch ());
      int second = filter::date::numerical_second (local_seconds);
      int minute = filter::date::numerical_minute (local_seconds);
      int hour = filter::date::numerical_hour (local_seconds);
      [[maybe_unused]] int weekday = filter::date::numerical_week_day (local_seconds);
      
      // Run once per second.
      if (second == previous_second) continue;
      previous_second = second;

      // Every second: Deal with queued and/or active tasks.
      tasks_run_check ();
      
      // Every second:
      // Check whether client sends/receives Bibles and Consultation Notes and other stuff.
      sendreceive_queue_sync (minute, second);
      // Log any connections that have come in.
      developer_logic_log_network_write ();

      // Run the part below every so many seconds.
      int fraction = second / 5;
      if (fraction != previous_fraction) {
        previous_fraction = fraction;
      }
      
      // Run the part below once per minute.
      if (minute == previous_minute) continue;
      previous_minute = minute;

      // Every minute send out queued email.
      if (!tasks_logic_queued (task::send_email))
        tasks_logic_queue (task::send_email);

#ifdef HAVE_CLOUD
      // Check for new mail every five minutes.
      // Do not check more often with gmail else the account may be shut down.
      if ((minute % 5) == 0) {
        tasks_logic_queue (task::receive_email);
      }
#endif

      // At the ninth minute after every full hour rotate the journal.
      // The nine is chosen, because the journal rotation will summarize the send/receive messages.
      // In case send/receive happens every five minutes, it is expected that under normal circumstances
      // the whole process of sending/receivning will be over, so summarization can then be done.
      if (minute == 9) tasks_logic_queue (task::rotate_journal);
      
      // Sending and receiving Bibles to and from the git repository.
      // On a production website running on an inexpensive virtual private server,
      // with 512 Mbyte of memory and a fast network connection,
      // sending and receiving two Bibles takes more than 15 minutes when there are many changes.
      bool sendreceive = ((hour == 0) && (minute == 5));
      bool repeat = ((minute % 5) == 0);
      if (sendreceive || repeat) {
        sendreceive_queue_all (sendreceive);
      }
      
#ifdef HAVE_CLOUD
      // Deal with the changes in the Bible made per user.
      // Deal with notifications for the daily changes in the Bibles.
      // This takes a few minutes on a production machine with two Bibles and changes in several chapters.
      // It runs in a server configuration, not on a client.
      if ((hour == 0) && (minute == 20)) {
        changes_logic_start ();
      }
#endif

#ifdef HAVE_CLOUD
      // Run the checks on the Bibles.
      // This takes 15 minutes on a production machine with two Bibles.
      if ((hour == 0) && (minute == 30)) {
        checks::logic::start_all ();
      }
#endif

      // Database maintenance and trimming.
      // It takes a few minutes on a production machine.
      if ((hour == 0) && (minute == 50)) {
        tasks_logic_queue (task::maintain_database);
      }

#ifdef HAVE_CLOUD
      // File cache trimming.
      // https://github.com/bibledit/cloud/issues/364
      // This used to be done once a day, and the trimming left files for multiple days.
      // This way of doing things led to a full disk when disk space was tight.
      // The new way of trimming on the Cloud is to do the trimming every hour.
      // And to leave files in the files cache for only a couple of hours.
      if (minute == 10) {
        tasks_logic_queue (task::trim_caches);
      }

#endif

#ifdef HAVE_CLOUD
      // Export the Bibles to the various output formats.
      // This may take an hour on a production machine.
      // This hour was in PHP. In C++ it is much faster.
      if ((hour == 1) && (minute == 10)) {
        export_logic::schedule_all ();
      }
#endif
      
      // Delete expired temporal files.
      if ((hour == 2) && (minute == 0)) {
        tasks_logic_queue (task::clean_tmp_files);
      }
      
      // Re-index Bibles and notes.
      // Only update missing indexes.
      if ((hour == 2) && (minute == 0)) {
        Database_State::create ();
        database::config::general::set_index_bibles (true);
        tasks_logic_queue (task::reindex_bibles);
        database::config::general::setIndexNotes (true);
        tasks_logic_queue (task::reindex_notes);
      }
      
      // Actions for a demo installation.
      if (minute == 10) {
        if (config::logic::demo_enabled ()) {
          tasks_logic_queue (task::clean_demo);
        }
      }
      
#ifdef HAVE_CLOUD
      // Sprint burndown.
      // It runs every hour in the Cloud.
      // The script itself determines what to do at which hour of the day or day of the week or day of the month.
      if (minute == 5) {
        tasks_logic_queue (task::sprint_burndown);
      }
#endif

#ifdef HAVE_CLOUD
      // Bibledit Cloud quits at midnight.
      // This is to be sure that any memory leaks don't accumulate too much
      // in case Bibledit Cloud would run for months and years.
      // The shell script notices that the binary has quit, and restarts the binary again.
      if (hour == 0) {
        if (minute == 1) {
          if (!database::config::general::getJustStarted ()) {
            if (tasks_run_active_count ()) {
              Database_Logs::log ("Server is due to restart itself but does not because of active jobs");
            } else {
              Database_Logs::log ("Server restarts itself");
              exit (0);
            }
          }
        }
        // Clear flag in preparation of restart next minute.
        // This flag also has the purpose of ensuring the server restarts once during that minute,
        // rather than restarting repeatedly many times during that minute.
        if (minute == 0) {
          database::config::general::setJustStarted (false);
        }
      }
#endif
      
#ifdef HAVE_CLOUD
      // Email notes statistics to the users.
      if ((hour == 3) && (minute == 0)) {
        tasks_logic_queue (task::notes_statistics);
      }
#endif

	
#ifdef HAVE_CLOUD
      // Update SWORD modules and other web resources once a week.
      if (weekday == 1) {
        // Refresh.
        if ((hour == 3) && (minute == 5)) {
          tasks_logic_queue (task::refresh_sword_modules);
          tasks_logic_queue (task::refresh_web_resources);
        }
        // Update installed SWORD modules, shortly after the module list has been refreshed.
        if ((hour == 3) && (minute == 15)) {
          tasks_logic_queue (task::update_sword_modules);
        }
      }
#endif

#ifdef HAVE_CLOUD
      // The Cloud updates the list of USFM resources once a week.
      if (weekday == 1) {
        if ((hour == 3) && (minute == 10)) {
          tasks_logic_queue (task::list_usfm_resources);
        }
      }
#endif

#ifdef HAVE_CLOUD
      // Keep the Google Translate access token current.
      // From experiments it appears that the token is valid for one hour.
      // So before the hour has expired, renew the token again.
      google_translate_authentication_token_age_minute++;
      if (google_translate_authentication_token_age_minute > 50) {
        tasks_logic_queue(task::get_google_access_token);
        google_translate_authentication_token_age_minute = 0;
      }
#endif

    } catch (const std::exception & e) {
      Database_Logs::log (e.what ());
    } catch (const std::exception * e) {
      Database_Logs::log (e->what ());
    } catch (...) {
      Database_Logs::log ("A general internal error occurred in the timers");
    }
  }
}