Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/v0.2.0 #152

Merged
merged 40 commits into from
Feb 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
1c36731
Fixes legacy logger
racheldaniel Nov 18, 2022
652eda7
Initial pass at removing legacy logging
racheldaniel Dec 6, 2022
666e781
Update log file output to use json format
racheldaniel Dec 7, 2022
f9d0c9b
Updates server logging to send events
racheldaniel Dec 7, 2022
ac06e11
Removes outdated comment
racheldaniel Dec 7, 2022
d63a729
Support partial parsing (#151)
racheldaniel Jan 9, 2023
92dd55e
resolves merge conflicts
racheldaniel Jan 9, 2023
23b23f3
Merge branch 'feature/server-on-core-1.5' of github.com:dbt-labs/dbt-…
racheldaniel Jan 9, 2023
ef59eaa
Core integration playground (#129)
ChenyuLInx Jan 12, 2023
52adba7
Merging latest main
racheldaniel Jan 17, 2023
34d3cc4
Upgrade FastAPI version in requirements.txt and add httpx to dev-requ…
jenniferjsmmiller Jan 19, 2023
479d1a4
Accept project path in addition to state_id (#154)
racheldaniel Jan 20, 2023
fc3a38e
Fixes broken tests (#156)
racheldaniel Jan 23, 2023
cec0320
Fix profile for async endpoint (#157)
racheldaniel Jan 27, 2023
b380581
Fixes shutdown and removes middleware
racheldaniel Jan 30, 2023
f2f5279
Fixes response_model as called out by community member on main branch
racheldaniel Jan 30, 2023
b2a88bb
Resolves merge conflicts
racheldaniel Jan 30, 2023
b3ccc38
Sync dbt endpoint (#161)
racheldaniel Feb 1, 2023
11b5ff7
Add task status callback (#164)
jp-dbt Feb 8, 2023
4c85644
make server working with dbt-core main (#167)
ChenyuLInx Feb 14, 2023
fec173e
Control server write locations (#166)
racheldaniel Feb 15, 2023
c90ccb9
Accept a task ID as part of the request and, if present, use it when …
jp-dbt Feb 16, 2023
bd84ae0
Adds error handling for json conversion
racheldaniel Feb 21, 2023
1945b6f
Include all exceptions in error handling. (#169)
dichenqiandbt Feb 23, 2023
8a5318f
Fix bug of not chdir back (#175)
dichenqiandbt Feb 23, 2023
4bcba85
Fix tests. (#173)
dichenqiandbt Feb 23, 2023
64c7732
Merging latest main
racheldaniel Feb 23, 2023
6797958
Update actions (#176)
racheldaniel Feb 27, 2023
6699d43
Removes conditional on test, tailors to branch (#181)
racheldaniel Feb 27, 2023
5d98ba9
fixes formatting
racheldaniel Feb 27, 2023
3f2ee12
fixes formatting
racheldaniel Feb 27, 2023
831cbd2
Testing installations in one line
racheldaniel Feb 27, 2023
07a9256
Undoes consolidaiton to single line
racheldaniel Feb 27, 2023
3809953
Adds quotes to head installs
racheldaniel Feb 27, 2023
2b34dc0
Adds 1.5.0b1 to github action
racheldaniel Feb 28, 2023
e675fb6
Adds prerelease flag
racheldaniel Feb 28, 2023
bdd765c
RUNTIME-733 Add smoke tests (#170)
dichenqiandbt Feb 28, 2023
60826ec
Fixes linting
racheldaniel Feb 28, 2023
2cbdd4b
Removes conditionals in github actions
racheldaniel Feb 28, 2023
f1d64de
Removes additional branch-- to be managed separately
racheldaniel Feb 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changes/unreleased/Features-20230117-083848.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
kind: Features
body: With this PR, dbt-server users/clients can pass a project path directly through
/parse rather than sending a dictionary of file contents to /push. If a user does
this, they can then call other endpoints such as /async/dbt and /compile without
a state_id, and the server will default to using that project path.
time: 2023-01-17T08:38:48.019196-06:00
custom:
Author: racheldaniel
Issue: "155"
PR: "154"
9 changes: 9 additions & 0 deletions .changes/unreleased/Features-20230130-160207.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
kind: Features
body: This PR adds a new synchronous endpoint, which will block and return command
results rather than return a task_id. These tasks are not added to the db, and do
not output logs
time: 2023-01-30T16:02:07.497161-06:00
custom:
Author: racheldaniel
Issue: "162"
PR: "161"
7 changes: 7 additions & 0 deletions .changes/unreleased/Features-20230206-120426.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
kind: Features
body: Add new task status callback functionality to the async dbt endpoint
time: 2023-02-06T12:04:26.954999-05:00
custom:
Author: jp-dbt
Issue: "165"
PR: "164"
7 changes: 7 additions & 0 deletions .changes/unreleased/Features-20230221-183401.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
kind: Features
body: Add smoke test.
time: 2023-02-21T18:34:01.400318-08:00
custom:
Author: dichenqiandbt
Issue: "727"
PR: "170"
8 changes: 8 additions & 0 deletions .changes/unreleased/Under the Hood-20221221-112702.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
kind: Under the Hood
body: Upgrade FastAPI version in requirements.txt and add httpx to dev-requirements.txt
to resolve error handling issue with underlying FastAPI dependency
time: 2022-12-21T11:27:02.990803-08:00
custom:
Author: jenniferjsmmiller
Issue: "599"
PR: "149"
8 changes: 8 additions & 0 deletions .changes/unreleased/Under the Hood-20230222-124703.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
kind: Under the Hood
body: Update github actions to test by dbt branch and deploy different images based
on branch (0.1.latest)
time: 2023-02-22T12:47:03.781432-06:00
custom:
Author: racheldaniel
Issue: "172"
PR: "171"
7 changes: 7 additions & 0 deletions .changes/unreleased/Under the Hood-20230227-113905.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
kind: Under the Hood
body: Only run tests for github actions on appropriate branch
time: 2023-02-27T11:39:05.03617-06:00
custom:
Author: racheldaniel
Issue: "182"
PR: "181"
45 changes: 19 additions & 26 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ jobs:
name: test code
runs-on: ubuntu-latest
timeout-minutes: 3
strategy:
matrix:
dbt-core:
- version: "1.5.0-pre"
package: "dbt-core~=1.5.0b1"
prerelease: true

steps:
- name: checkout repo
uses: actions/checkout@v3
Expand All @@ -43,43 +50,29 @@ jobs:
uses: actions/setup-python@v4
with:
python-version: "3.8"

- name: run tests
- name: run tests - releases
run: |
pip install -r requirements.txt -r dev-requirements.txt
pip install dbt-core dbt-postgres
pip install ${{ (matrix.dbt-core.prerelease && '--pre') || '' }} ${{ matrix.dbt-core.package }} dbt-postgres dbt-snowflake
pytest

- name: run tests - head
run: |
pip install -r requirements.txt -r dev-requirements.txt
pip install "https://github.com/dbt-labs/dbt-core/archive/HEAD.tar.gz#egg=dbt-core&subdirectory=core"
pip install "https://github.com/dbt-labs/dbt-core/archive/HEAD.tar.gz#egg=dbt-postgres&subdirectory=plugins/postgres"
pip install "https://github.com/dbt-labs/dbt-snowflake/archive/HEAD.tar.gz#egg=dbt-snowflake"
pytest

build-push:
name: build and push dbt server images
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
dbt-core:
- version: "1.0.0"
package: "dbt-core~=1.0.0"
- version: "1.0.1"
package: "dbt-core~=1.0.1"
- version: "1.1.0-pre"
package: "dbt-core~=1.1.0b1"
- version: "1.1.0-latest"
package: "dbt-core~=1.1.1"
- version: "1.2.0-pre"
package: "dbt-core~=1.2.0b1"
prerelease: true
- version: "1.2.0-latest"
package: "dbt-core~=1.2.0"
- version: "1.3.0-pre"
package: "dbt-core~=1.3.0b1"
prerelease: true
- version: "1.3.0-latest"
package: "dbt-core~=1.3.0"
- version: "1.4.0-pre"
package: "dbt-core~=1.4.0b1"
- version: "1.5.0-pre"
package: "dbt-core~=1.5.0b1"
prerelease: true
- version: "1.4.0-latest"
package: "dbt-core~=1.4.0"
dbt-database-adapter:
- name: snowflake
package: dbt-snowflake
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ sql_app.db
/env
/venv
dbt-core-server-exploration/
dbt.log
.DS_Store
23 changes: 6 additions & 17 deletions dbt_server/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,15 @@ def create_task(db: Session, task: schemas.Task):
return db_task


def set_task_running(db: Session, task: schemas.Task):
def set_task_state(
db: Session, task: schemas.Task, state: models.TaskState, error: str
):
db_task = get_task(db, task.task_id)
db_task.state = models.TaskState.RUNNING
db.commit()
db.refresh(db_task)
return db_task


def set_task_done(db: Session, task: schemas.Task):
db_task = get_task(db, task.task_id)
db_task.state = models.TaskState.FINISHED
db.commit()
db.refresh(db_task)
return db_task
db_task.state = state

if error:
db_task.error = error

def set_task_errored(db: Session, task: schemas.Task, error: str):
db_task = get_task(db, task.task_id)
db_task.state = models.TaskState.ERROR
db_task.error = error
db.commit()
db.refresh(db_task)
return db_task
4 changes: 3 additions & 1 deletion dbt_server/database.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from dbt_server.services.filesystem_service import get_db_path

SQLALCHEMY_DATABASE_URL = "sqlite:///./sql_app.db"

SQLALCHEMY_DATABASE_URL = f"sqlite:///{get_db_path()}"

engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
Expand Down
22 changes: 8 additions & 14 deletions dbt_server/helpers.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import os
from dbt_server.exceptions import InternalException
from pydantic import BaseModel


class Args(BaseModel):
profile: str = None


def extract_compiled_code_from_node(result_node_dict):
Expand All @@ -23,13 +18,12 @@ def extract_compiled_code_from_node(result_node_dict):
return compiled_code


def set_profile_name(args=None):
# If no profile name is passed in args, we will attempt to set it from env vars
# If no profile is set, dbt will default to reading from dbt_project.yml
def get_profile_name(args=None):
# If no profile name is passed in args, we will attempt to get it from env vars
# If profile is None, dbt will default to reading from dbt_project.yml
if args and hasattr(args, "profile") and args.profile:
return args
if os.getenv("DBT_PROFILE_NAME"):
if args is None:
args = Args()
args.profile = os.getenv("DBT_PROFILE_NAME")
return args
return args.profile
env_profile_name = os.getenv("DBT_PROFILE_NAME")
if env_profile_name:
return env_profile_name
return None
50 changes: 32 additions & 18 deletions dbt_server/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,24 @@
from datetime import datetime
from typing import Optional

try:
from dbt.events.functions import STDOUT_LOG, FILE_LOG
except (ModuleNotFoundError, ImportError):
STDOUT_LOG = None
FILE_LOG = None

from dbt.events.eventmgr import EventLevel
from dbt.events.base_types import BaseEvent
from pythonjsonlogger import jsonlogger
from dbt_server.models import TaskState

from dbt_server.models import TaskState

ACCOUNT_ID = os.environ.get("ACCOUNT_ID")
ENVIRONMENT_ID = os.environ.get("ENVIRONMENT_ID")
WORKSPACE_ID = os.environ.get("WORKSPACE_ID")

dbt_event_to_python_root_log = {
EventLevel.DEBUG: logging.root.debug,
EventLevel.TEST: logging.root.debug,
EventLevel.INFO: logging.root.info,
EventLevel.WARN: logging.root.warn,
EventLevel.ERROR: logging.root.error,
}


class CustomJsonFormatter(jsonlogger.JsonFormatter):
def add_fields(self, log_record, record, message_dict):
Expand All @@ -37,9 +41,9 @@ def add_fields(self, log_record, record, message_dict):
log_record["workspaceID"] = WORKSPACE_ID


# setup json logging
# setup json logging for stdout and datadog
logger = logging.getLogger()
logger.setLevel(logging.INFO)
logger.setLevel(logging.DEBUG)
stdout = logging.StreamHandler()
if os.environ.get("APPLICATION_ENVIRONMENT") in ("dev", None):
formatter = logging.Formatter(
Expand All @@ -55,16 +59,11 @@ def add_fields(self, log_record, record, message_dict):
)
stdout.setFormatter(formatter)
logger.addHandler(stdout)
dbt_server_logger = logging.getLogger("dbt-server")
dbt_server_logger.setLevel(logging.DEBUG)
GLOBAL_LOGGER = dbt_server_logger

# remove handlers from these loggers, so
# that they propagate up to the root logger
# for json formatting
if STDOUT_LOG and FILE_LOG:
STDOUT_LOG.handlers = []
FILE_LOG.handlers = []
# Use standard python logger for all dbt-server logs-- these will be sent to
# stdout but will not be written to task log files
DBT_SERVER_LOGGER = logging.getLogger("dbt-server")
DBT_SERVER_LOGGER.setLevel(logging.DEBUG)

# make sure uvicorn is deferring to the root
# logger to format logs
Expand All @@ -91,6 +90,21 @@ def configure_uvicorn_access_log():
ual.handlers = []


# Push event messages to root python logger for formatting
def log_event_to_console(event: BaseEvent):
logging_method = dbt_event_to_python_root_log[event.log_level()]
if logging_method == logging.root.debug:
# Only log debug level for dbt-server logs
return
logging_method(event.info.msg)


# TODO: Core is still working on a way to add a callback to the eventlogger using the
# newer format. We will still need to do this for events emitted by core
# EVENT_MANAGER.callbacks.append(log_event_to_console)


# TODO: This should be some type of event. We may also choose to send events for all task state updates.
@dataclass
class ServerLog:
state: TaskState
Expand Down
1 change: 0 additions & 1 deletion dbt_server/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from sqlalchemy import Column, String
from enum import Enum

from .database import Base


Expand Down
41 changes: 24 additions & 17 deletions dbt_server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@
from dbt_server.database import engine
from dbt_server.services import dbt_service, filesystem_service
from dbt_server.views import app
from dbt_server.logging import GLOBAL_LOGGER as logger, configure_uvicorn_access_log
from dbt_server.logging import DBT_SERVER_LOGGER as logger, configure_uvicorn_access_log
from dbt_server.state import LAST_PARSED
from dbt_server.exceptions import StateNotFoundException
from sqlalchemy.exc import OperationalError

# The default checkfirst=True should handle this, however we still
# see a table exists error from time to time
try:
models.Base.metadata.create_all(bind=engine, checkfirst=True)
except OperationalError as err:
logger.debug(f"Handled error when creating database: {str(err)}")

models.Base.metadata.create_all(bind=engine)
dbt_service.disable_tracking()


Expand All @@ -25,23 +31,25 @@ class ConfigArgs(BaseModel):
def startup_cache_initialize():
"""
Initialize the manifest cache at startup. The cache will only be populated if there is
a latest-state-id.txt file pointing to a state folder with a pre-compiled manifest.
If any step fails (the latest-state-id.txt file is missing, there's no compiled manifest,
or it can't be deserialized) then continue without caching.
a latest-state-id.txt file or latest-project-path.txt file pointing to a state or project folder
with a pre-compiled manifest. If any step fails (the latest-state-id.txt file is missing,
there's no compiled manifest, or it can't be deserialized) then continue without caching.
"""

# If an exception is raised in this method, the dbt-server will fail to start up.
# Be careful here :)

latest_state_id = filesystem_service.get_latest_state_id(None)
if latest_state_id is None:
logger.info("[STARTUP] No latest state found - not loading manifest into cache")
latest_project_path = filesystem_service.get_latest_project_path()
root_path = filesystem_service.get_root_path(latest_state_id, latest_project_path)

if root_path is None:
logger.info(
"[STARTUP] No latest state or project found - not loading manifest into cache"
)
return

manifest_path = filesystem_service.get_path(latest_state_id, "manifest.msgpack")
logger.info(
f"[STARTUP] Loading manifest from file system (state_id={latest_state_id})"
)
manifest_path = filesystem_service.get_path(root_path, "manifest.msgpack")
logger.info(f"[STARTUP] Loading manifest from file system (path={root_path})")

try:
manifest = dbt_service.deserialize_manifest(manifest_path)
Expand All @@ -50,7 +58,7 @@ def startup_cache_initialize():
return
except (StateNotFoundException):
logger.error(
f"[STARTUP] Specified latest state not found - not loading manifest (state_id={latest_state_id})"
f"[STARTUP] Specified root path not found - not loading manifest (path={root_path})"
)
return

Expand All @@ -59,15 +67,14 @@ def startup_cache_initialize():
target_name = None
config_args = ConfigArgs(target=target_name)

source_path = filesystem_service.get_root_path(latest_state_id)
manifest_size = filesystem_service.get_size(manifest_path)
config = dbt_service.create_dbt_config(source_path, config_args)
config = dbt_service.create_dbt_config(root_path, config_args)

LAST_PARSED.set_last_parsed_manifest(
latest_state_id, manifest, manifest_size, config
latest_state_id, latest_project_path, root_path, manifest, manifest_size, config
)

logger.info(f"[STARTUP] Cached manifest in memory (state_id={latest_state_id})")
logger.info(f"[STARTUP] Cached manifest in memory (path={root_path})")


@tracer.wrap
Expand Down
Loading