Skip to content

Commit 8eca941

Browse files
committed
back part pre-relize
1 parent 3c7a6be commit 8eca941

5 files changed

Lines changed: 174 additions & 36 deletions

File tree

main.py

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
import argparse
2-
from src import make_extract, transform_article_debug, transform_article_web, load_news, init_database, create_news_tables, load_web_pipeline, make_extract_web, make_extract_debug
32
import logging
43

4+
from src import (
5+
init_database,
6+
create_app_users_table,
7+
create_search_requests_table,
8+
create_articles_table,
9+
create_user_news_table,
10+
create_request_stats_table,
11+
create_news_tables,
12+
run_pipeline_for_web_user,
13+
run_debug_pipeline
14+
)
15+
516
logging.basicConfig(
617
level=logging.INFO,
718
format = "%(asctime)s | %(levelname)s | %(name)s | %(message)s"
@@ -39,46 +50,42 @@ def parse_args():
3950
help="Amount of articels on 1 page"
4051

4152
)
53+
parser.add_argument(
54+
"--debug",
55+
action="store_true"
56+
)
57+
parser.add_argument(
58+
"--user_id",
59+
type=int,
60+
default=1
61+
)
62+
parser.add_argument(
63+
"--serch_request_id",
64+
type=int,
65+
default=1
66+
)
4267
return parser.parse_args()
4368

44-
def pipeline_for_web_user(user_id: int, search_request_id: int, key_word: str, limit: int, page_size: int, debug:bool = False) -> int:
69+
def init_all_tables(debug: bool) -> None:
70+
init_database()
71+
create_app_users_table()
72+
create_articles_table()
73+
create_request_stats_table()
74+
create_search_requests_table()
75+
create_user_news_table()
4576
if debug:
46-
args = parse_args()
47-
key_word = args.keyword
48-
limit = args.limit
49-
page_size = args.page_size
50-
user_id = 1
51-
search_request_id = 1
52-
num_of_news = 0
53-
page = 1
54-
while num_of_news < limit:
55-
remaining = limit - num_of_news
56-
if debug:
57-
raw_file_name, raw_articles_count = make_extract_debug(key_word, page, page_size)
58-
if raw_articles_count == 0:
59-
logger.warning("there is no more artical")
60-
break
61-
clean_file_name = transform_article_debug(raw_file_name, key_word, page)
62-
result_num_of_news = load_news(clean_file_name, max_rows=remaining)
63-
else:
64-
payload, raw_articles_count = make_extract_web(key_word, page, page_size)
65-
if raw_articles_count == 0:
66-
logger.warning("there is no more artical")
67-
break
68-
clean_data, stats = transform_article_web(payload)
69-
result_num_of_news = load_web_pipeline(user_id, search_request_id, clean_data, stats)
70-
71-
num_of_news += result_num_of_news
72-
page += 1
73-
logger.info(f"{num_of_news} news on key word {key_word} already aploaded")
74-
return num_of_news
77+
create_news_tables()
78+
7579

7680
def main()-> None:
81+
args = parse_args()
7782
logger.info("Starting pipeline, init database, build table..")
7883
try:
79-
init_database()
80-
create_news_tables()
81-
loaded = pipeline_for_web_user()
84+
init_all_tables(debug=args.debug)
85+
if args.debug:
86+
loaded = run_debug_pipeline(args.keyword, args.limit, args.page_size)
87+
else:
88+
loaded = run_pipeline_for_web_user(args.user_id, args.search_request_id, args.ketword, args.limit, args.page_size)
8289
logger.info("Pipline finished. loaded rows: %s", loaded)
8390
except Exception as e:
8491
logger.exception("pipeline failed: %s", e)

src/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .extract import make_extract_debug, make_extract_web
22
from .transform import transform_article_web, transform_article_debug
33
from .load import load_news, load_web_pipeline
4-
from .db import init_database, create_news_tables
4+
from .db import init_database, create_news_tables, create_app_users_table, create_search_requests_table, create_articles_table, create_user_news_table, create_request_stats_table
5+
from .pipeline import run_pipeline_for_web_user, run_debug_pipeline

src/extract.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def import_to_raw_json(data:dict[str, Any], key_word: str, page: int) -> str:
2323

2424

2525

26-
def make_extract_debug( key_word: str, page: int = 1, page_size: int = 100) -> str:
26+
def make_extract_debug( key_word: str, page: int = 1, page_size: int = 100) -> tuple[str, int]:
2727
params = {
2828
"apiKey": settings.KEY_API,
2929
"language":settings.langueage,

src/pipeline.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import logging
2+
from src import (
3+
make_extract_web,
4+
make_extract_debug,
5+
transform_article_web,
6+
transform_article_debug,
7+
load_web_pipeline,
8+
load_news,
9+
)
10+
11+
logger = logging.getLogger(__name__)
12+
13+
def run_pipeline_for_web_user(user_id: int, search_request_id: int, key_word: str, limit: int, page_size: int) -> int:
14+
num_of_news = 0
15+
page = 1
16+
while num_of_news < limit:
17+
payload, raw_articles_count = make_extract_web(key_word, page, page_size)
18+
if raw_articles_count == 0:
19+
logger.warning("there is no more artical")
20+
break
21+
clean_data, stats = transform_article_web(payload)
22+
result_num_of_news = load_web_pipeline(user_id, search_request_id, clean_data, stats)
23+
num_of_news += result_num_of_news
24+
page += 1
25+
logger.info(f"{num_of_news} news on key word {key_word} already aploaded")
26+
return num_of_news
27+
28+
def run_debug_pipeline(keyword: str, limit:int, page_size: int) -> int:
29+
num_of_news = 0
30+
page = 1
31+
while num_of_news < limit:
32+
max_rows = limit - num_of_news
33+
new_file_name, raw_articles_count = make_extract_debug(keyword, page, page_size)
34+
if raw_articles_count == 0:
35+
logger.warning("there is no more artical")
36+
break
37+
clean_data = transform_article_debug(new_file_name,keyword,page)
38+
result_num_of_news = load_news(clean_data, max_rows)
39+
num_of_news += result_num_of_news
40+
page += 1
41+
logger.info(f"{num_of_news} news on key word {keyword} already aploaded")
42+
return num_of_news

src/worker.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import logging
2+
import time
3+
4+
from src.db import get_cursor
5+
from config.config import settings
6+
from src import run_pipeline_for_web_user
7+
8+
logging.basicConfig(
9+
level=logging.INFO,
10+
format="%(asctime)s | %(levelname)s |%(name)s | %(message)s"
11+
)
12+
logger = logging.getLogger(__name__)
13+
14+
def get_nearest_queue() -> dict | None:
15+
query = """ SELECT
16+
id, user_id, keyword, language, limit_count, page_size
17+
FROM search_requests
18+
WHERE status = 'queued'
19+
ORDER BY created_at
20+
LIMIT 1 """
21+
with get_cursor(settings.db_news) as (_, cur):
22+
cur.execute(query)
23+
return cur.fetchone()
24+
25+
def mark_as_running(search_request_id: int) -> None:
26+
query = """ UPDATE search_requests
27+
SET
28+
status = 'running',
29+
started_at = NOW(),
30+
error_text = NULL
31+
WHERE id = %s
32+
"""
33+
with get_cursor(settings.db_news) as (conn, cur):
34+
cur.execute(query, (search_request_id,))
35+
conn.commit()
36+
37+
def mark_as_success(search_request_id: int) -> None:
38+
query = """UPDATE search_requests
39+
SET
40+
status = 'success',
41+
finished_at = NOW()
42+
WHERE id = %s """
43+
with get_cursor(settings.db_news) as (conn, cur):
44+
cur.execute(query, (search_request_id,))
45+
conn.commit()
46+
def mark_as_error(search_request_id: int, error_text: str) -> None:
47+
query = """UPDATE search_requests
48+
SET
49+
status = 'ERROR',
50+
finished_at = NOW(),
51+
error_text = %s
52+
WHERE id = %s"""
53+
with get_cursor(settings.db_news) as (conn,cur):
54+
cur.execute(query, (error_text, search_request_id))
55+
conn.commit()
56+
57+
def one_request() -> bool:
58+
request_row = get_nearest_queue()
59+
if not request_row:
60+
return False
61+
search_request_id = request_row["id"]
62+
user_id = request_row["user_id"]
63+
keyword = request_row["keyword"]
64+
limit_count = request_row["limit_count"]
65+
page_size = request_row["page_size"]
66+
logger.info(f"Pipeline starts for {user_id} on {search_request_id} by keyword {keyword}")
67+
mark_as_running(search_request_id)
68+
69+
try:
70+
amount_of_articles = run_pipeline_for_web_user(user_id, search_request_id, keyword, limit_count, page_size)
71+
72+
mark_as_success(search_request_id)
73+
logger.info(f"Pipeline finished successfully for {user_id} on {search_request_id} by {keyword}")
74+
logger.info(f"pushed {amount_of_articles} articles")
75+
except Exception as e:
76+
logger.exception(f"Pipeline for {user_id} on {search_request_id} by {keyword} failed: {e}")
77+
mark_as_error(search_request_id, e)
78+
return True
79+
80+
def run_worker_loop(pull_interval: int = 3) -> None:
81+
logger.info("Worker started")
82+
while True:
83+
processed = one_request()
84+
if not processed:
85+
time.sleep(pull_interval)
86+
87+
if __name__ == "__main__":
88+
run_worker_loop()

0 commit comments

Comments
 (0)