Repository: chaoss/augur

Issue:
Augur is limited to 32767 starts
**Description:**
So due to various problems, our augur instance restart a lot (crashes due to some change in some upstream library). 

This morning, i was greeted with a error message:
```
Jan 25 10:27:47 augur.osci.io podman[3980072]: sqlalchemy.exc.DataError: (psycopg2.errors.SequenceGeneratorLimitExceeded) nextval: reached maximum value of sequence "config_id_seq" (32767)
```

I spare the complete analysis, but that's cause by several factor. The table in question has this schema:
```
augur=# \d augur_operations.config
                                        Table "augur_operations.config"
    Column    |       Type        | Collation | Nullable |                       Default 
--------------+-------------------+-----------+----------+-----------------------------------------------------
 id           | smallint          |           | not null | nextval('augur_operations.config_id_seq'::regclass)
 section_name | character varying |           | not null |
 setting_name | character varying |           | not null |
 value        | character varying |           |          |
 type         | character varying |           |          |
Indexes:
    "config_pkey" PRIMARY KEY, btree (id)
    "unique-config-setting" UNIQUE CONSTRAINT, btree (section_name, setting_name)
```

The id value is autogenerated by a sequence. The code that trigger the error is in https://github.com/chaoss/augur/blob/main/augur/application/db/session.py#L96 , the function insert_data. My understanding is that it is used for massive insert, and so use a insert on conflict thanks to:
```
        stmnt = s.dialects.postgresql.insert(table).returning(*returning_args).values(data)
```

The generated SQL is something like this:
```
INSERT INTO augur_operations.config (section_name, setting_name, value, type) VALUES (%(section_name_m0)s, %(setting_name_m0)s, %(value_m0)s, %(type_m0)s), (%(section_name_m1)s, %(setting_name_m1)s, %(value_m1)s, %(type_m1)s) ON CONFLICT (section_name, setting_name) DO UPDATE SET section_name = excluded.section_name, setting_name = excluded.setting_name, value = excluded.value, type = excluded.type
```

However, it seems that this will always increment the counter, as explained on this SO answer:
https://stackoverflow.com/questions/37204749/serial-in-postgres-is-being-increased-even-though-i-added-on-conflict-do-nothing

Even if nothing is done, the sequence is incremented, while in a ideal world, we want it to be incremented only if a new line is added.

So when augur is started, the insert_data function is called by `config.load_config_from_dict(default_config)` in https://github.com/chaoss/augur/blob/main/augur/application/cli/config.py (in the function init_config).

Since our instance is crashing constantly (because systemd is configured to restart on crash, and it crash due to https://github.com/eventlet/eventlet/issues/781, my next problem to fix as it didn't fixed itself as I expected last week), the augur application is exhausting the sequence, and so refuse to crash.




Discussion:
@mscherer : We identified some significant limitations with eventlet (including the one you note here). Augur version 0.44.0 to the current Augur version version 0.44.2 have eliminated this issue. Note in the installation instructions that we are now using rabbitmq, which is an additional dependency. We added rabbitmq because it enables us to process data collect tasks at ~80% of what eventlet enabled, and redis-server was not up for the load.
@mscherer : Let me know if my response addressed your issue by closing this issue. Alternately, let me know what I missed in my response. 
@mscherer : These are the detailed, exhaustively validated installation instructions for augur 0.44.x: https://github.com/chaoss/augur/blob/main/docs/new-install.md
So, it should solve the issue by not crashing, but the root cause (adding a new line on each restart) would still be here, no ?

Resolving patch:
diff --git a/augur/application/config.py b/augur/application/config.py
--- a/augur/application/config.py
+++ b/augur/application/config.py
@@ -1,4 +1,5 @@
 import sqlalchemy as s
+from sqlalchemy import or_, and_, update
 import json
 from typing import List, Any, Optional
 import os
@@ -275,7 +276,24 @@ def add_or_update_settings(self, settings: List[dict]):
                 setting["type"] = None
 
         #print(f"\nsetting: {settings}")
-        self.session.insert_data(settings,Config, ["section_name", "setting_name"])
+        #self.session.insert_data(settings,Config, ["section_name", "setting_name"])
+
+            #Check if setting exists.
+            query = self.session.query(Config).filter(and_(Config.section_name == setting["section_name"],Config.setting_name == setting["setting_name"]) )
+
+            if execute_session_query(query, 'first') is None:
+                self.session.insert_data(setting,Config, ["section_name", "setting_name"])
+            else:
+                #If setting exists. use raw update to not increase autoincrement
+                update_query = (
+                    update(Config)
+                    .where(Config.section_name == setting["section_name"])
+                    .where(Config.setting_name == setting["setting_name"])
+                    .values(value=setting["value"])
+                )
+
+                self.session.execute(update_query)
+                self.session.commit()
        
 
     def add_section_from_json(self, section_name: str, json_data: dict) -> None:


Test patch: